Morphia/MongoDb, Using and Index with FindAndModify() - mongodb

I am currently in the process of refactoring some of our mongo querying code to get rid of methods deprecated in Morphia 1.3. I am running into an issue when trying to run a find and Modify query with an index . At the moment our legacy code is setting an index on the query in this fashion:
ds.createQuery(Entity.class).hintIndex("index")
I have removed it to be in line with morphia 1.3 and the code now looks something like this :
new FindOptions.modifier("$hint", "index");
return query.asList(findOptions);
As a result we do not set the index on the query until actually running it. This is fine of get queries, less so for upsert ones.
To replace the deprecated findAndModify : findAndModify(Query<T> query, UpdateOperations<T> operations, boolean oldVersion, boolean createIfMissing), morphia is asking to use findAndModify(Query, UpdateOperations, FindAndModifyOptions)
In this case, I would have expected to have a modifier method in the FindAndModifyOptions object to be able to set an index, when running the query. I can't seem to be able to do something like this:
FindAndModifyOptions findOptions = new FindOptions();
findOptions.modifier("$hint", SUGGESTION_CONTENT_TYPE_INDEX_NAME);
return datastore.findAndModify(query, updateOperations, findAndModifyOptions);
Can someone advise on how to pass the index? Is it possible to do it via the FindAndModifyOptions object ?if not, what would be the best way to set the index for the upsert query

Related

Update a MongoDB document in JAVA without explicit conversion

I am using the mongo-db java driver 3.8 and work with the collection as follows:
MongoDatabase md=mongoClient.getDatabase(databaseName);
MongoCollection<ConstructionPlan> collection=md.getCollection(plansCollectionName,abc.class);
collection.insertOne(item);
collection.find(Filters.eq("itemId", id),abc.class).first();
With this code I do not have to do any conversion. I was looking for a way to update an document the same way. I am thinking on something like this:
abc anABCObject=collection.find(Filters.eq("itemId", id),ConstructionPlan.class).first();
//updates...
collection.update(anABCObject);
Is there a way to update an existing document without BSON conversion? (I was unable to find it....)
updateOne for updating document fields using update operators.
You need replaceOne which takes the replacement document.
collection.replaceOne(
Filters.eq("itemId", id),
anABCObject
);

Morphia Upserting Field as int64 instead of in32

I've written an operation upsert a document to Mongo using Morphia.
I have a field which I want to save as an int32, but after the upsert it is inserted as int64.
I have made sure that I convert the long as an int using Long.intValue() and the object that Morphia serializes back to, the member field is int. I have also checked the UpdateOperations.ops to see what morphia is upserting.
The upsert operation is:
UpdateOperations<Test> ops = datastore.createUpdateOperations(Test.class)
.set("test_field", testField.intValue())
The current version of Mongo I am using is 3.0.
Any help would be appreciated!
Thanks!
EDIT:
Looking at the update query operation in Morphia it is:
{$set={test_field=11}}
I managed to find out the solution. The query for the upsert was querying on the test_field as a long rather than an int. Mongo 3.0 sees this as the type to insert - however running on Mongo 3.2, there is no issue and it will upsert with the type specified in the upsert operation, not the query.

Does MongoDB simplify query logic?

Are the following logical equivalent queries handled by the server differently?
{"Name":"1"}
{$and:[{"Name":"1"},{$or:[{"Name":"1"},{"Tag":"a"}]}]}
Since the second query include the "Tag" field, does it affect index usage?
If you want to experiment and see what mongo is doing for each query you can use an explainable object in the mongo shell.
You can create it with a cursor (https://docs.mongodb.org/manual/reference/method/cursor.explain/):
db.example.find({a:17, b:55}).sort({b:-1}).explain()
Or you can create an explainable object and execute queries with it (https://docs.mongodb.org/v3.0/reference/explain-results/#explain-output):
var exp = db.example.explain()
exp.help() // see what you can do with it
exp.find({a:17, b:55}).sort({b:-1}) // execute query over the object
I cannot answer your question since you do not provide information about the indexes defined in your database, but using this you can see it by yourself in the "queryPlanner" section. If it's using an index it shows "IXSCAN" at "stage" field.

Refering MongoDB indexes with find() / aggregate()

Is there any way to force a find() or aggregate() query to refer/see a particular existing index in MongoDB. I am asking about the the scenario when a collection has more than one compound indexes.
Yes, $hint is there for that. As mentioned in the documentation, you can use it like that:
db.users.find().hint( { age: 1 } )
What you put in argument is the definition of the index, and not its name. This query would force the use of the index on the age field. I'm not sure though whether it works for aggreate() call as well or not.
Aggregation does not support $hint. There is a open item in MongoDB
https://jira.mongodb.org/browse/SERVER-7944

Spring data mongoDB GeoNear query with excluding fields

I don't know if I am doing something wrong or it is a bug.
I have the following code:
Query criteria = new Query(Criteria.where("locationTime").gte(
"date-time"));
criteria.fields().exclude("friends");
NearQuery query = NearQuery.near(point).maxDistance(maxDistance)
.num(limit).query(criteria);
GeoResults<Profile> result = mongoTemplate
.geoNear(query, Profile.class);
I am executing the query and profiles near by retrieved correctly according to distance and the "locationTime" criteria but it seems to ignore the excluded field and retrieving the profiles with their friends.
When I use simple query the exclude/include fields works perfectly.
I looked every where and could not find any resemble use-case, please let me know if i am doing something wrong.
Thanks.
There's no way to limit the fields with a geoNear command, as far as I know.
I looked into calling executeCommand to try to work around the limitations of Spring Data, but it looks like they don't even have a way to do it from the raw command.