mongodb java $in query with $regex - java

I am trying to write $in query with $regex in mongo+java. It's not working in mongo shell either. What I mean is I don't get any results but no query parse error either.
Here's the final query I got from Java Debugger at the line where I say collection.find(finalQuery)
{"$and": [
{"$or": [
{"country": "united states"}
]},
{"businesses": {
"$in": [
{"$regex": "^.*cardinal.*health.*$"},
{"$regex": "^.*the.*hartford.*$"}
]
}}
]}
Java Code snipet for Above query:
Set<Pattern> businesses = new HashSet<Pattern>();
for(String st: srchTerms) {
businesses.add(Pattern.compile("^"+st.trim()+"$"));
}
srchTermQuery.append("businesses", new BasicDBObject("$in", businesses));
However, following query works in mongo shell but I don't know how to write it into java:
{"registering_organization": {
"$in": [
/^.*cardinal.*health.*$/,
/^.*the.*hartford.*$/
]
}}
Java Code add double quotes around regex if we try to define it as a string.

The behavior you're seeing might be a bug, however as an alternative you can write your query like this
Pattern pattern = Pattern.compile("(^aaa$)|(^bbb$)");
srchTermQuery.append("businesses", pattern);
Not pretty but it seem to do the trick

You're not going to be able to convert:
{"businesses" : {
"$in":[
/^.*cardinal.*health.*$/,
/^.*the.*hartford.*$/
]
}}
directly into a Java regex. This is not a bug, it's because the Java driver uses $regex format when creating regex queries to avoid any ambiguity.
The $regex documentation states that
db.collection.find({field: /acme.*corp/});
db.collection.find({field: {$regex: 'acme.*corp'}});
So your Java-generated query of:
{"businesses": {
"$in": [
{"$regex": "^.*cardinal.*health.*$"},
{"$regex": "^.*the.*hartford.*$"}
]
}}
is exactly equivalent of the query you were trying to convert:
{"businesses": {
"$in": [
/^.*cardinal.*health.*$/,
/^.*the.*hartford.*$/
]
}}
In summary, the Java you've written is already the correct way to convert the query you wanted. I've run it in my own test and it returns the expected results.
Perhaps if you included some sample documents that you expect to be returned by the query we could help further?

I had a need to list all keys beginning with a specified string. The following worked for me in CLI:
db.crawlHTML.count({"_id": /^1001/})
The following was the Java implementation:
public List<String> listKeysLike(DB mongoDB, String likeChars) throws Exception {
DBCollection dbCollection = this.getHTMLCollection(mongoDB, TESTPROD);
List<String> keyList = new ArrayList<String>();
BasicDBObject query = new BasicDBObject();
String queryString = "^" + likeChars.trim() ; // setup regex
query.put("_id", java.util.regex.Pattern.compile(queryString));
DBCursor cursor = dbCollection.find(query);
while (cursor.hasNext()) { // _id used as the primary key
BasicDBObject obj = (BasicDBObject) cursor.next();
String tempString = obj.getString("_id");
keyList.add(tempString);
} // while
return keyList;
}
NB: The "TESTPROD" just tells me which of two databases I should be using.

You have to use mongodb regex notation rather than putting it in a string
db.somecollection.find({records: {$in: [/.*somestring.*/]}})

Related

Using queryStringQuery and boolQuery for date range

I am using Java to run queries on ElasticSearch. I'm having difficulties running range queries using boolQuery() API and queryStringQuery as input. here's the code:
QueryBuilder stringQuery = QueryBuilders.queryStringQuery(query);
QueryBuilder finalQuery = QueryBuilders.boolQuery().should(stringQuery);
The data field for date has the following format:
"startedOn" : { "type" : "date", "format": "yyyy-MM-dd HH:mm:ss.SSSSSS" }
and I am using queries like these:
StartedOn < 2020-06-29
StartedOn : [2020-06-20 TO 2020-06-25]
But none of them seem to return the correct results. Am I missing something here?
Thanks.

MongoDB java driver create Document with $in filter

I think this should be easy to do, but I just couldn't figure it out.
What I'm trying to achieve is this query
{inbox:{$in:["main","fun-inbox"]} ,status:"Open"}
I managed to make it work like this
Bson q = Filters
.and(Filters
.in("inbox", inboxes),
Filters
.eq("status", statusID));
but is not the same thing because I used the $and operator
Can this be done using Document ?
Here is what I've tried and I know is wrong the way I define it, but I'll put the example just to better understand what I'm trying to achieve
Document q1 = new Document()
.append("inbox", Filters.in("inbox", inboxes))
.append("status", statusID);
What you have is correct and it is not explicitly $anded.
Java Mongo driver behind the scene figures out when to $and and when to not.
For example
Without $and
Bson bson = Filters.and(Filters.in("inbox", inboxes), Filters.eq("status", status));
BsonDocument bsonDocument = bson.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry());
System.out.print(bsonDocument.toString()); //{ "inbox" : { "$in" : inboxes }, "status" : status }
With $and
Bson bson = Filters.and(Filters.in("inbox", inboxes), Filters.eq("inbox", inbox));
BsonDocument bsonDocument = bson.toBsonDocument(BsonDocument.class, MongoClient.getDefaultCodecRegistry());
System.out.print(bsonDocument.toString()); //{ "$and" : [{ "inbox" : { "$in" : inboxes } }, { "inbox" : inbox }] }
Converted your query to java code to return Iterable Document type
FindIterable<Document> iterable = database.getCollection("mails").find(new Document("inbox", new Document("$in", inValues)).append("status", "open"));
and inValues is an ArrayList as
ArrayList<String> inValues = new ArrayList<String> ();
inValues.add("main");
inValues.add("fun-inbox");

How to delete mongodb document with two conditions one with $gt operator?

I would like to retrieve the following information:
delete from database where name = 'AAA' and age>20;
but for MongoDB in Java. Essentially, it should delete the document that contain the word AAA and age greater than 20 in them. I know that there is the $in operator in MongoDB, but how do I do the same in Java, using the Java driver? I've been trying to look for it everywhere but am getting nothing. I've tried:
query = new BasicDBObject("age", new BasicDBObject("$gt", "20"), new BasicDBObject("name", "AAA"));
JSON which i want to delete is like this.
{"school" : "NewSchool" , "name" : "AAA" , "age" : "50"}
What you want is the find-term:
{
"name" : "AAA",
"age" : { $gt : 20 }
}
Construct this as your basic DB object, or simply use the new 3.x Filters to create the Bson for you. (As I personally only use 3.x, here's the appropriate example):
MongoClient client = ...
MongoDatabase db = client.getDatabase(...);
MongoCollection<Document> coll = db.getCollection(...);
coll.deleteMany(Filters.and(Filters.eq("name", "AAA"), Filters.gt("age", 20)));

MongoDB querying with Java API

Here is the sample document of my MongoDB:
user:{
_id:1,
name:'xyz',
age:12,
mobile:21321312,
transaction:[{
trans_id:1,
prod:'a',
purchasedAt:ISODate("2015-02-01"),
},
{
trans_id:2,
prod:'b',
purchasedAt:ISODate("2015-02-01")
},
{
trans_id:3,
prod:'c',
purchasedAt:ISODate("2014-11-24")
}]
,...
}
My query looks like:
db.user.find({transaction:{$elemMatch:{prod:'a', purchasedAt:ISODate("2015-02-01")}}, transaction:{$elemMatch:{prod:{$nin:['b','c']}, purchasedAt:ISODate("2015-02-01")}}}).count()
I am trying to get the user count who have purchased product 'a' on date "2015-02-01" but not have purchased product b & c on same day.
So while trying to do this in Java with the query:
coll.find(new BasicDBObject().append("transaction", new BasicDBObject("$elemMatch", new BasicDBObject("prod", 'a').append("purchasedAt", Date))).append("transaction", new BasicDBObject("$elemMatch", new BasicDBObject("prod", new BasicDBObject("$nin",['b','c'])).append("purchasedAt", Date)));
I have also tried:
coll.find(new BasicDBObject("transaction", new BasicDBObject("$elemMatch", new BasicDBObject("prod", 'a').append("purchasedAt", Date))).append("transaction", new BasicDBObject("$elemMatch", new BasicDBObject("prod", new BasicDBObject("$nin",['b','c'])).append("purchasedAt", Date)));
where Date is "2015-02-01" in util.Date object.
I found out that Java ignores the $in part of the query, i.e. it ignores {transaction:{$elemMatch:{prod:'a', purchasedAt:ISODate("2015-02-01")}} & performs only $nin part.
I found out it by DBCursor object.
Here's the output of the cursor:
Cursor: Cursor id=0, ns=mydb.user, query={ "transaction" : { "$elemMatch" : { "prod" : { "$nin" : [ "b" , "c"]} , "purchasedAt" : { "$date" : "2015-02-01T00:00:00.000Z"}}}}, numIterated=0, readPreference=primary
Because of this my result is inaccurate. I wonder why the exact same query works well in Mongo shell but doesn't with Java API. Is there anything wrong with my query structure?
My guess is that this question is now moot, but, if you still do not consider it answered, are you looking for the "$not" operator, which can check for non-existance sort of.

MongoDB Date query JAVA

Im trying to do a query to get all the values from my DB wich each have a date. One example:
leadTime: [
{
date: ISODate("2014-03-19T23:00:00Z"),
value: 25.8
},
{
date: ISODate("2014-03-20T23:00:00Z"),
value: 31.299999999999997
},
{
date: ISODate("2014-03-21T23:00:00Z"),
value: 34.4
}
]
enter code here
My code is:
DBObject query=new BasicDBObject("group",group);
DBObject serieData= col.findOne(query,new BasicDBObject(serie, 1));
if (serieData != null) {
List<DBObject> data = (List<DBObject>) serieData.get(serie);
for (DBObject item : data) {
result.add(new HistoryData((Date) item.get("date"),(Double) item.get("value")));
}
Now I want to get the values that the date is bigger than a date that I pass by parameter. The query I did is this:
DBObject query=new BasicDBObject("group",group)
.append("date", new BasicDBObject("$gte", parameterDate))
;
But I always receive the result empty, can you help me? sorry for my english and than
Assuming that leadTime is a field in your documents, your query has to look like this
DBObject query=new BasicDBObject("group",group)
.append("leadTime.date", new BasicDBObject("$gte", parameterDate))
;
The way you did it, MongoDB would have searched for a date field in your document root:
{ _id: "Foo",
date: ISODate("2014-03-19T23:00:00Z"),
[...]
}
Queries in MongoDB don't make a difference if the queried field is a single value or an array, so using the dot notation on a field which holds an array of subdocuments is perfectly valid.
What you want to do is not possible with a simple query.
But if you still want to do it in mongodb you need to use the aggregation framework, with something like that :
db.<col_name>.aggregate( [ { $unwind : "$group" }, { $match : {'group.date': { $gte : parameterDate } } ] )
this a js command, but you should be able to translate it easly in Java Driver (you can also add a $project operation to just return needed fields).

Categories