How to specify UUID in mongo $where clause - java

I have an object that was stored via mongo-java-driver. Object uses java.util.UUID for its _id field. Following is presentation of object via mongo shell:
> db.b.find()
{ "_id" : BinData(3,"zUOYY2AE8WZqigtb/Tqztw==") }
I have a requirement to process searching via $where clause. I use following code to do it:
Mongo m = new Mongo();
DBCollection coll = m.getDB("a").getCollection("b");
coll.save(new BasicDBObject("_id", UUID.randomUUID()));
// ??? - don't know what should be specified
DBObject query = new BasicDBObject("$where", "this[\"_id\"] == " + ???);
coll.find(query).count()
The question is what should I specify instead of ??? to make it work?
Thanks for any help.

My invesigation shown that only one way to do it is rewriting a query in object based way (I mean migration of $where clause part to BasicDBObject based query). In such case mongo-java-driver supports java.util.UUID without any additional effort.

Related

Java MongoDB: querying with numberLong field

How do I query in mongoDB using the mongoDB java driver for a numberLong field?
I tried this according to this SO post: Java Mongodb numberlong query but it does not work.
Query query= new Query();
query.addCriteria(Criteria.where("time").is("NumberLong("+article.getDate()+")"));
I also tried this where article.getDate() has a return type of Long and it does not work:
query.addCriteria(Criteria.where("time").is(article.getDate()));
There is no new NumberLong object within the java driver to use.
https://docs.mongodb.org/manual/core/shell-types/ suggest that one uses NumberLong() wrapper but it is only for the javascript shell, not for java.
MongoClient client = new MongoClient();
MongoDatabase mongoDb = client.getDatabase("test");
MongoCollection<Document> mongoCollection = mongoDb
.getCollection("numberFormatTest");
mongoCollection.drop();
Document smith = new Document("name", "Smith").append("age", 30)
.append("profession", "Programmer")
.append("phoneNo", "9848022338");
Document jones = new Document("name", "Jones").append("age", 30)
.append("profession", "Hacker")
.append("phoneNo", "9000000000000");
printJson(smith);
printJson(jones);
// mongoCollection.insertMany(asList(smith,jones));
System.out.println("Phone number: "
+ Long.valueOf(smith.getString("phoneNo")).longValue());
The above piece of code might work for you. At the moment, I tried with find but it will work for updates as well.
Even in the above link shared by you,NumberLong wrapper saves the field value in string datatype not as a long datatype. The below statement proves it.
"The NumberLong() wrapper accepts the long as a string:"
I think it was just my oversight in this case. The query here actually works:
query.addCriteria(Criteria.where("time").is(article.getDate()));
I had called my object field as "date" instead of "time", which met it did not get picked up when i queried. Changing it as follows made it work properly.
query.addCriteria(Criteria.where("date").is(article.getDate()));

How to compare 2 fields in Spring Data MongoDB using query object

What seems almost natural in simple SQL is impossible in mongodb.
Given a simple document:
{
"total_units" : 100,
"purchased_unit" : 60
}
I would like to query the collection, using spring data Criteria class, where "total_units > purchased_units".
To my understanding it should be as trivial as any other condition.
Found nothing to support this on Spring api.
You can use the following pattern:
Criteria criteria = new Criteria() {
#Override
public DBObject getCriteriaObject() {
DBObject obj = new BasicDBObject();
obj.put("$where", "this.total_units > this.purchased_units");
return obj;
}
};
Query query = Query.query(criteria);
I don't think Spring Data API supports this yet but you may need to wrap the $where query in your Java native DbObject. Note, your query performance will be fairly compromised since it evaluates Javascript code on every record so combine with indexed queries if you can.
Native Mongodb query:
db.collection.find({ "$where": "this.total_units > this.purchased_units" });
Native Java query:
DBObject obj = new BasicDBObject();
obj.put( "$where", "this.total_units > this.purchased_units");
Some considerations you have to look at when using $where:
Do not use global variables.
$where evaluates JavaScript and cannot take advantage of indexes.
Therefore, query performance improves when you express your query
using the standard MongoDB operators (e.g., $gt, $in). In general, you
should use $where only when you can’t express your query using another
operator. If you must use $where, try to include at least one other
standard query operator to filter the result set. Using $where alone
requires a table scan. Using normal non-$where query statements
provides the following performance advantages:
MongoDB will evaluate non-$where components of query before $where
statements. If the non-$where statements match no documents, MongoDB
will not perform any query evaluation using $where. The non-$where
query statements may use an index.
As far as I know you can't do
query.addCriteria(Criteria.where("total_units").gt("purchased_units"));
but would go with your suggestion to create an additional computed field say computed_units that is the difference between total_units and purchased_units which you can then query as:
Query query = new Query();
query.addCriteria(Criteria.where("computed_units").gt(0));
mongoOperation.find(query, CustomClass.class);
Thanks #Andrew Onischenko for the historic good answer.
On more recent version of spring-data-mongodb (ex. 2.1.9.RELEASE), I had to write the same pattern like below:
import org.bson.Document;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
// (...)
Criteria criteria = new Criteria() {
#Override
public Document getCriteriaObject() {
Document doc = new Document();
doc.put("$where", "this.total_units > this.purchased_units");
return doc;
}
};
Query query = Query.query(criteria);
One way is this:
Criteria c = Criteria.where("total_units").gt("$purchased_unit");
AggregationOperation matchOperation = Aggregation.match(c);
Aggregation aggregation = Aggregation.newAggregation(matchOperation);
mongoTemplate.aggregate(aggregation, "collectionNameInStringOnly", ReturnTypeEntity.class);
Remember to put collection name in string so as to match the spellings of fields mentioned in criteria with fields in database collection.

How to do MongoDB query with JavaScript expression in Java code , like in Mongo shell

1.
I know how to query with JavaScript expression in Mongo shell
( collection name is resource_phys. field name is val which defined as String type and contains only numeric value ) :
//in Mongo shell:
var query1 = ("Number(this.val)>-1 && Number(this.val)<3")
db.resource_phys.find(query1)
//result found
2.
Now, I want to do the same thing in Java code but cannot find any API to support JavaScript. I solicit your help to give some hints.
3.P.s.
If the field val is numeric type, I am aware of using operator $gt and $lt :
//in Java codes:
DBCollection coll = db.getCollection("resource_phys");
DBObject query2 = new BasicDBObject("val",new BasicDBObject("$gt",-1).append("lt",3));
DBCursor cursor = coll.find(query2);
//result got in cursor
The form of query you are doing in the shell is actually just a shortcut form of the $where operator. So you would translate like this:
DBObject query = new BasicDBObject(
"$where",
"Number(this.val)>-1 && Number(this.val)<3"
);
Please note the documentation though, as running JavaScript is not a good idea for performance. You really should convert your strings to be actual numeric values.

Parameterized queries with Java and MongoDB

Can you do parameterized queries with Java and MongoDB - kind of like prepared statements with JDBC?
What I'd like to do is something like this. Set up a query that takes a date range - and then call it with different ranges. I understand that DBCursor.find(...) doesn't work this way - this is kind of pseudo-code to illustrate what I'm looking for.
DBCollection dbc = ...
DBObject pQuery = (DBObject) JSON.parse("{'date' : {'$gte' : ?}, 'date' : {'$lte' : ?}}");
DBCursor aprilResults = dbc.find(pQuery, "2012-04-01", "2012-04-30");
DBCursor mayResults = dbc.find(pQuery, "2012-05-01", "2012-05-31");
...
MongoDB itself doesn't support anything like this, but then again, it doesn't take too much sense as it needs to send the query over to the server every time anyway. You can simply
construct the object in your application yourself, and just modify specific parts by updating the correct array elements.
You should use Jongo, an API over mongo-java-driver.
Here is an example with parameterized query :
collection.insert("{'date' : #}", new Date(999));
Date before = new Date(0);
Date after = new Date(1000);
Iterable<Report> results = collection.find("{'date' : {$gte : #}, 'date' : {$lte : #}}", before, after).as(Report.class);

Exists Query for multilple Document in Mongodb using java driver

If we want to check that the record is exists in Collection or not, then there is an operator $exists in Mongodb. But if we want to know multiple records exists in Collection then how can we check that in single query using java driver?
For Example I have two document:
{"key": "val1"}
{"key": "val2"}
Now if I want to check that 'val1' and 'val2' is exist or not then how can we do that in single query using java driver?
Note: here field name is same in both the documents.
You need to use $in operator for that
db.collection.find( { key : { $in : ['val1','val2'] } } );
equivalent java code might like this
List<string> values = new ArrayList<string>();
values.add("val1")
values.add("val2")
BasicDBObject query = new BasicDBObject();
query.put("key", new BasicDBObject("$in", values));
DBCursor cursor = yourcollection.find(query);
am not much of a java guy, this is going to be more or less same.

Categories

Resources