0
  1. What is the correct syntax for creating $or condition in embedded document in MongoDB Java driver?

  2. Is it actually possible to get a cursor to embedded documents?

Suppose I have the following document:

{
    statuses: [{
        {
            streamName: A
        }{
            statusA: 0
        }{
            statusB: 1
        }
    },
    {
        {
            streamName: B
        }{
            statusA: 0
        }{
            statusB: 1
        }
    }]
}

I would also like to get cursor to sub documents (in array of statuses) that has at least one status bigger than 0.

This is how I did it but it didn't work:

List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
DBObject query = new BasicDBObject();

obj.add(new BasicDBObject ("statuses", 
        new BasicDBObject ("statusA",
        new BasicDBObject ("$gt",0 ) )));

obj.add(new BasicDBObject ("statuses",
        new BasicDBObject ("statusB" ,
        new BasicDBObject ("$gt",0 ) )));

query.put("$or",obj)
db.find(collectionName,query)

I didn't find any documentation on that.

s7vr
  • 73,656
  • 11
  • 106
  • 127
Ohad
  • 1,563
  • 2
  • 20
  • 44

1 Answers1

3

What you have translates to

{ "$or" : [ { "statuses" : { "statusA" : { "$gt" : 0}}} , { "statuses" : { "statusB" : { "$gt" : 0}}}]}

which is used for whole document comparison.

For comparing fields inside an embedded arrays/doc you've to use dot notation.

{ "$or" : [ { "statuses.statusA" : { "$gt" : 0}} , { "statuses.statusB" : { "$gt" : 0}}]}

The equliavent java code is below

List<BasicDBObject> obj = new ArrayList<BasicDBObject>();
DBObject query = new BasicDBObject();
obj.add(new BasicDBObject ("statuses.statusA", new BasicDBObject ("$gt",0 ) ));
obj.add(new BasicDBObject ("statuses.statusB" , new BasicDBObject ("$gt",0 ) ));
query.put("$or",obj);

Alternatively you can use $elemMatch to run matches on embedded arrays. Similar to what you've but $elemMatch applies condition to each fields.

Something like

{ "statuses" : { "$elemMatch" : { "$or" : [ { "statusA" : { "$gt" : 0}} , { "statusB" : { "$gt" : 0}}]}}}

Java Code

BasicDBList obj = new BasicDBList();
obj.add(new BasicDBObject ("statusA",new BasicDBObject ("$gt",0 ) ));
obj.add(new BasicDBObject ("statusB",new BasicDBObject ("$gt",0 ) ));
DBObject query = new BasicDBObject("statuses", new BasicDBObject("$elemMatch", new BasicDBObject("$or",obj)));

Count the no of matching occurrences.

Bson count = new Document("statuses", Document.parse("{$size:{\n" +
            "            $filter: {\n" +
            "               input: \"$statuses\",\n" +
            "               as: \"status\",\n" +
            "               cond: { \"$or\" : [ {$gt:[\"$$status.statusA\", 0]} , {$gt:[\"$$status.statusB\", 0]}]}\n" +
            "            }\n" +
            "         }}"));
Bson project = new Document("$project", count);
col.aggregate(Arrays.asList(project));
s7vr
  • 73,656
  • 11
  • 106
  • 127
  • can I use DBObject instead of Document? – Ohad Jan 23 '18 at 19:14
  • what is a Bson? – Ohad Jan 23 '18 at 19:17
  • can you explain a bit why you did the syntax in that way ? in the count example – Ohad Jan 23 '18 at 19:18
  • so you use parse instead if using list of dbobjects? – Ohad Jan 23 '18 at 19:31
  • and sorry one more thing, why do you use twice $$? is it because it's embedded field? – Ohad Jan 23 '18 at 19:34
  • can you show an alternative answer without using the parse but with a list of dbobjects? – Ohad Jan 23 '18 at 19:39
  • 1
    Np.Yes you can . Bson is an interface to allow conversion from higher level class to specific implementation. Check all the implementations of Bson to understand more. Its just a format to escape the double quotes and its directly copied from java ide. You can use single quotes to inline the whole string. Col is db collection reference. Yes, you can create a list of db objects instead. $$ to refer the user variable define in the flilter stage to access individual element in array. yes I can update the answer in a little bit. – s7vr Jan 23 '18 at 19:41
  • one more thing, why do you do Arrays.asList(project)) ? – Ohad Jan 23 '18 at 19:49
  • That's just to change the single/multiple values into arraylist for aggregate method which accepts list of stages. [Here](https://stackoverflow.com/questions/41467386/query-a-document-and-all-of-its-subdocuments-that-match-a-condition-in-mongodb/41467578#41467578) is one DBObject implementation for $filter – s7vr Jan 23 '18 at 20:24
  • can you please show the mongodb syntax for the aggregation query ? – Ohad Jan 24 '18 at 08:46
  • Try `db.collection.aggregate({"count":{$size:{$filter: {input: "$statuses",as: "status",cond: { "$or" : [ {$gt:["$$status.statusA", 0]} , {$gt:["$$status.statusB", 0]}]}}}}});` – s7vr Jan 24 '18 at 14:49