MongoDB: mixing $ all and $ elemMatch

I have a set of "elements" of 5 elements, each of which has an identifier and an array

{ _id: ObjectId("51c21bec162c138d9d0001a7"), tags: [ { name: "a", type: "tag" }, { name: "b", type: "tag" }, { name: "c", type: "note" } ] } { _id: ObjectId("51c21ca22c69904840000178"), tags: [ { name: "a", type: "tag" }, { name: "d", type: "tag" }, { name: "c", type: "note" } ] } { _id: ObjectId("51c21cc1478cf6691a0001b4"), tags: [ { name: "d", type: "tag" }, { name: "b", type: "tag" }, { name: "c", type: "note" } ] } { _id: ObjectId("51c22292162c13b1ff000222"), tags: [ { name: "a", type: "tag" }, { name: "d", type: "tag" }, { name: "e", type: "note" } ] } { _id: ObjectId("51c222e926d602a57d0001d8"), tags: [ { name: "a", type: "tag" }, { name: "d", type: "note" }, { name: "c", type: "note" } ] } 

The goal is to return all elements with tags "a" and "d", where the tags have a type tag. You might have thought that would do this:

 find({"tags.name":{"$all":["a","d"]}, "tags.type":'tag'}) 

returns 3 documents, which is incorrect, but I found out that this query is executing or. So I'm trying to use "$ elemMatch" to do this, in what I thought was the most intuitive way, but

 find({"tags":{"$elemMatch":{'name':{'$all':["a","d"]}, "type":'tag'}}}) 

does not return documents.

The same query if I need only those elements with tags 'a':

 find({"tags":{"$elemMatch":{'name':{'$all':["a"]}, "type":'tag'}}}) 

presumably because $ all gets mapped to something like $ eq.

In the end, I found that for my initial GOAL , the following should be done:

 find({"tags":{"$all":[{'$elemMatch':{'name':"a", "type":'tag'}}, {'$elemMatch':{'name':"d", "type":'tag'}} ]}}) 

returns two valid documents.

But this syntax is terrible! I need to expand the array ["a", "d"] myself in the request. What if I write a general query mechanism and want to say that several fields of an embedded document are arrays, and I want a specific subset of the values ​​from each array?

Is there a better way to do this? Best syntax?

+4
source share
1 answer

What you ultimately achieved is the right decision. This could be an improvement for programmatically constructing the $elemMatch rule $elemMatch .

Consider the following python:

 match_rules = [] for tag in query_tags: match_rules.append({ '$elemMatch': { 'name': tag 'type': 'tag' } }) collection.find({"tags":{"$all": match_rules}}) 
+2
source

Source: https://habr.com/ru/post/1487166/


All Articles