I am using Morphia, the Pojo mapper for MongoDB, and I find difficult a task that in my view should be very simple: getting an object by id. I am able to find all the objects in a collection but I cannot figure out the simple task of querying using an id I got from the list. I am actually talking about the ObjectId. If I try to render it in JSON I see
This question seems incomplete.
It also seems like the answer to you question is on the Morphia QuickStart page. Seems to be as simple as follows.
Datastore ds = morphia.createDatastore("testDB");
String hotelId = ...; // the ID of the hotel we want to load
// and then map it to our Hotel object
Hotel hotel = ds.get(Hotel.class, hotelId);
So you'll definitely need more details.
Datastore ds = morphia.createDatastore("testDB");
String hotelId = "516d41150364a6a6697136c0"; // the ID of the hotel we want to load
ObjectId objectId = new ObjectId(hotelId);
// and then map it to our Hotel object
Hotel hotel = ds.get(Hotel.class, objectId);
If you're finding by id and the id is provided by the user (means that it could be whatever type of data), you shouldn't use the solutions given above.
As explained in the documentation, an ObjectId consists of 12 bytes, so if you pass something else to new ObjectId(myValue), your code will throw an IllegalArgumentException.
Here is how I implemented the method to find by id :
public Model findById(String id) throws NotFoundException {
if (!ObjectId.isValid(id)) {
throw new NotFoundException();
}
ObjectId oid = new ObjectId(id);
Model m = datastore().find(Model.class).field("_id").equal(oid).get();
if (m == null) {
throw new NotFoundException();
}
return m;
}
The previous explanation used the deprecated methods: datastore().find(Model.class).field("_id").equal(oid).get(); My variant of it on Morphia 2.2.10:
public Optional<Hotel> findById(final String id) {
if (!ObjectId.isValid(id)) {
throw new SomeException();
}
final Query<Hotel> query = datastore.find(Hotel.class)
.filter(eq("_id", new ObjectId(id)));
return Optional.ofNullable(query.first());
}
Related
I am trying to write a method that returns me IDs (as a List ) of all records from a collection that have a certain status.
I am looking for a solution, but unfortunately I cannot find anything correct.
I currently have something like this:
List<String> getAllLecturersIdList() {
MongoCollection<Document> collection.mongoTemplate.getCollection("lecturers");
MongoCursor<Document> cursor = collection.find().iterator();
ArrayList<String> listOfIDS = new ArrayList<>();
while (cursor.hasNext()) {
listOfIDS.add(cursor.next().getObjectId("_id").toString());
}
return listOfIDS;
}
This method returns me a list of IDs of all lecturers.
The lecturer entity also has a "status" field with values like ACTIVE, LEAVE, FIRED and so on.
I would like to have only IDs of lecturers who have ACTIVE status to be returned to me.
How to do it to have only entities with ACTIVE status when returning from the collection, and not to clean the repository / services level?
Thanks for help in advance!
Important - I don't want an entity structure to be created in the application.
Therefore, the solution cannot contain a POJO / Entity Class and here is the problem (I cannot use e.g. Criteria, because every example is with defined entity )
You can fallback to the low level MongoOperations#executeQuery method if there is no result type mapping your query results:
List<String> getAllLecturersIdList() {
Query query = new Query();
query.fields().include("_id");
query.addCriteria(Criteria.where("status").is("ACTIVE"));
ArrayList<String> listOfIDS = new ArrayList<>();
mongoTemplate.executeQuery(query, "lecturers", document -> listOfIDS.add(document.getObjectId("_id").toString()));
return listOfIDS;
}
The following should work:
List<String> getAllLecturersIdList() {
MongoCollection<Document> collection.mongoTemplate.getCollection("lecturers");
MongoCursor<Document> cursor = collection.find().iterator();
ArrayList<String> listOfIDS = new ArrayList<>();
while (cursor.hasNext()) {
Document document = cursor.next();
if (document.getString("status") == "ACTIVE") {
listOfIDS.add(document.getObjectId("_id").toString());
}
}
return listOfIDS;
}
I'm using HIbernate search(5.8.2). The search works smoothly on every field except for the primary key. It returns an empty list when I pass anything to it. I followed the hibernate documentation, used #documentId annotation for primary key. What am I missing?
Here's my model:
#SuppressWarnings("serial")
#Entity
#Indexed
#Table(name = "MAIN",schema="maindb")
public class MAIN implements Serializable {
#Id
#DocumentId
private String poNo; // my primary key which has values like "PO123"
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
private String postatus;
My search function:
public List<?> search(String poNumber, String status) {
QueryBuilder qb =
fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(MAIN.class).get();
BooleanQuery.Builder finalLuceneQuery = new BooleanQuery.Builder();
org.hibernate.query.Query hibQuery =
fullTextSession.createFullTextQuery(finalLuceneQuery.build(),MAIN.class);
org.apache.lucene.search.Query querypono1 =
qb2.simpleQueryString().onField("poNo").matching(poNumber)
.createQuery();
org.apache.lucene.search.Query queryStatus =
qb.simpleQueryString().onField("po01_status")
.matching("postatus").createQuery();
finalLuceneQuery.add(querypono1, BooleanClause.Occur.MUST);
finalLuceneQuery.add(queryStatus , BooleanClause.Occur.MUST);
hibQuery.setFirstResult(0);
List<?> resultArchive = new ArrayList<String>();
try {
result = hibQuery.getResultList();
} catch (Exception e) {
e.printStackTrace();
// log.log(ERROR, "ERROR FETCHING RESULT LIST FROM DATABASE");
}
return result;
}
The issue is that "PO123" is transformed to "po123" by the simple query string parser. I wonder why, I have to check that, it's probably a bug, or it's at least an unexpected behavior.
That being said, you shouldn't use the simpleQuery() entry point for an exact matching.
Replace:
org.apache.lucene.search.Query querypono1 = qb2.simpleQueryString().onField("poNo").matching(poNumber).createQuery();
By:
org.apache.lucene.search.Query querypono1 = qb2.keyword().onField("poNo").matching(poNumber).createQuery();
(keyword() instead of simpleQueryString())
I will follow up on this issue though as it's not the behavior I would have expected. Thanks for raising it.
-> JIRA issue: https://hibernate.atlassian.net/browse/HSEARCH-3039 , will be included in the upcoming 5.10.0.Final.
The ask: a function to retrieve a single Entity from the Google App Engine Datastore based on a property that is not its Key or otherwise return null if no such object is found.
Here is the function I have currently:
public Entity find(DatastoreService datastore, String kind, String property, String value) {
Filter propertyFilter =
new FilterPredicate(property, FilterOperator.EQUAL, value);
Query q = new Query(kind).setFilter(propertyFilter);
List<Entity> results =
datastore.prepare(q).asList(FetchOptions.Builder.withDefaults());
if (results.isEmpty()) {
return null;
}
return results.get(0);
}
Is there a one-shot API I could use instead or are there any optimization suggestions?
You could use PreparedQuery#asSingleEntity():
public Entity find(DatastoreService datastore,
String kind, String property, String value)
throws TooManyResultsException {
Filter propertyFilter =
new FilterPredicate(property, FilterOperator.EQUAL, value);
Query q = new Query(kind).setFilter(propertyFilter);
return datastore.prepare(q).asSingleEntity();
}
The only real difference between this and your code is that the underlying query sets a LIMIT of 2.
I am currently trying to load info from a dynamo DB table using a LSI and dynamoDB mapper class. Assume i have the following code
Conisder this class
class Employee {
#DynamoDBHashKey
public String getID() {
return ID;
}
#DynamoDBRangeKey
public String getFirstName() {
return firstName;
}
#DynamoDBIndexRangeKey(localSecondaryIndexName = "my-lsi")
public String getLastName() {
return lastName;
}
public String getMyotherfield() {
return myotherfield;
}
}
Consider this piece of code to retrieve info using LSI and dynamoDB mapper
Employee obj = new Employee();
obj.setID("221");
obj.setLastName("SOMEONE");
DynamoDBQueryExpression<Employee> queryExpression = new DynamoDBQueryExpression<>();
queryExpression.setHashKeyValues(obj);
queryExpression.setIndexName("my-lsi");
queryExpression.setProjectionExpression("myotherfield");
PaginatedQueryList<Employee> paginatedQueryList = mapper.query(Employee.class, queryExpression);
Iterator<Employee> iterator = paginatedQueryList.iterator();
while (iterator.hasNext()) {
Employee pp = iterator.next();
// some code
}
[EDIT]
Is this the right way to query LSI with mapper?
If not what is a better way to fetch data from the table using LSI and dynamoDBMapper? (in terms of performance)
i also found this https://java.awsblog.com/post/Tx3GYZEVGO924K4/The-DynamoDBMapper-Local-Secondary-Indexes-and-You but its a 2013 link. I am not able to find latest documentation on querying with LSI and mapper.
Note that in the code you have given, you haven't set the range key at all. Use queryExpression.setRangeKeyConditions() to do so.
Here is a code sample:
Map<String, Condition> rangeKeyConditions = new HashMap<>();
rangeKeyConditions.put("lastName", new Condition()
.withComparisonOperator(ComparisonOperator.EQ)
.withAttributeValueList(new AttributeValue().withS("SOMEONE")));
queryExpression.setRangeKeyConditions(rangeKeyConditions);`
[Update]:
It is not sufficient (nor necessary) to set the range key value ("SOMEONE") in the object (obj), since that object is used only for setting the hashKey. Have a look at the examples here
I'm working with wordpress post metas and rest api, i've exposed to rest a meta field called "picture_collection" wich store data as an array of integers where every number represents the ID of an attachment.
I've then modified the response when interrogating the api to give me a list of links instead of the attachment ids, like this:
function get_pic_coll ($object, $field_name, $request) {
include_once dirname(__FILE__) . '/attach_coll.php';
$pic_coll = get_post_meta ($object['id'], $field_name, true);
$json_coll = array();
if($pic_coll != null || !empty($pic_coll)){
foreach ($pic_coll as $pic){
$media_id = $pic;
$link_med = wp_get_attachment_image_src($media_id, 'medium');
$link_full = wp_get_attachment_image_src($media_id, 'full');
$medium_size = $link_med[0];
$full_size = $link_full[0];
$obj = new attach_coll($media_id, $medium_size, $full_size);
$element = $obj->return_coll_object();
$json_coll[] = $element;
}
return $json_coll;
}
}
while the attach_coll object is:
class attach_coll{
public function __construct($media_id, $medium_url, $orig_url){
$this->attach_id = $media_id;
$this->medium_size_pic = $medium_url;
$this->full_size_pic = $orig_url;
}
private $attach_id;
private $medium_size_pic;
private $full_size_pic;
public function get_media_id(){
return $this->attach_id;
}
public function get_medium_pic(){
return $this->medium_size_pic;
}
public function get_orig_pic(){
return $this->full_size_pic;
}
public function return_coll_object(){
$ret_coll = array(
"ID" => $this->get_media_id(),
"medium" => $this->get_medium_pic(),
"full" => $this->get_orig_pic()
);
return $ret_coll;
}
}
Java side the things goes like this:
1)the user make a picture and upload her, he receive in exchange the ID of the attachment that is stored inside an Integers ArrayList.
2)when he has done the program update the post_meta passing to the api the entire list.
3)the program receive the response as a json containing the whole post with my custom field, it looks like this:
{...
"id":"someValue",
"title":"myTitle",
"pic_collection":[ {'ID':'picID','mediumSizePic':'someUrl', 'FullSizePic':'SomeOtherUrl},{...}],
The php code works well as i see from the ResponseBody the json i was expecting, the problem is that i'm getting an error 'gson expected a Integer and found an Object' that is logical because the pojo is defined like:
#SerializedName("pic_collection")
private List<Integer> idList = new ArrayList<Integer>();
public void setList(List<Integer> list){
this.idList=list;
}
I tried to change my list to:
List<PicCollection> picList = new ArrayList<PicCollection>();
public class PicCollection{
#SerializedName("ID")
private int picId;
#SerializedName("medium_size")
private String medSizeUrl;
#SerializedName("full_size")
private String fullSizeUrl;
Getters and Setters
}
But that just complicated everything up and didn't resolved the problem as i'm still having a the same gson error 'ID expecting an int but found an object' and no links returned at all.
A glimpse on the code to set the id's:
iterator=idList.iterator;
while(iterator.hasNext()){
FotoCollection fc = new FotoCollection();
fc.ID = iterator.next
What can i do to resove the problem? I need a custom converter?
I just created 2 objects:
One for the request and one for the response.