我有5个项目的“项目”集合,每个项目都有一个ID和一个数组

{ _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" } ]
}

此处的目标是返回所有带有标签“a”和“d”的项目,其中标签的类型为“标签”。 您可能以为这样可以做到:
find({"tags.name":{"$all":["a","d"]}, "tags.type":'tag'})

返回3个文档,这是错误的,但是我了解到该查询的结果为or。因此,然后我尝试使用“$ elemMatch”来执行此操作,我认为这是最直观的方法,但是
find({"tags":{"$elemMatch":{'name':{'$all':["a","d"]}, "type":'tag'}}})

不返回任何文档。

如果我只希望标记为“a”的项目有效,则使用相同的查询:
find({"tags":{"$elemMatch":{'name':{'$all':["a"]}, "type":'tag'}}})

大概是因为$ all被映射到$ eq之类的东西。

最终,我发现以下是我最初的GOAL 需要做的事情:
find({"tags":{"$all":[{'$elemMatch':{'name':"a", "type":'tag'}}, {'$elemMatch':{'name':"d", "type":'tag'}} ]}})

返回正确的两个文档。

但是这种语法太可怕了!我必须自行将数组[“a”,“d”]扩展到查询中。如果我正在编写一个通用查询引擎,并且想说嵌入式文档的多个字段是数组,并且我想要每个数组的值的某个子集,该怎么办?

有更好的方法吗?更好的语法?

最佳答案

您最终得出的是正确的解决方案。以编程方式构造$elemMatch规则数组可能是一种改进。

考虑下面的python:

match_rules = []
for tag in query_tags:
  match_rules.append({
    '$elemMatch': {
      'name': tag
      'type': 'tag'
    }
  })

collection.find({"tags":{"$all": match_rules}})

10-08 16:05