从$ in查询中返回匹配的元素

时间:2016-05-26 10:26:29

标签: mongodb mongodb-query pymongo aggregation-framework

我有几个遵循这种结构的文件:

{
  "queue-type": <integer>,
  "participants": [{
     "id": <integer>,
     "level": <level>,
     "flags": <integer>
  }]
}

participants.id上有一个多键索引。

在代码中,有一个查询查询,如下所示:db.queues.find({"participants.id": {"$in": [2, 3, 4]}}),其结果如下:

{"queue-type": 1, "participants": [{"id": 1, "level": 10, "flags":4},{"id": 2, "level": 10, "flags":8}]}
{"queue-type": 25, "participants": [{"id": 5, "level": 10, "flags":4},{"id": 15, "level": 10, "flags":8},{"id": 4, "level": 10, "flags":8}]}

有没有办法检索用于匹配查询的元素?类似的东西:

{"queue-type": 1, "_matched": 2, "participants": [{"id": 1, "level": 10, "flags":4},{"id": 2, "level": 10, "flags":8}]}
{"queue-type": 25, "_matched": 4, "participants": [{"id": 5, "level": 10, "flags":4},{"id": 15, "level": 10, "flags":8},{"id": 4, "level": 10, "flags":8}]}

PS:我试图避免在[2, 3, 4]participants数组中循环,因为它们更大。

实施例: 队列

{"queue-type": 1, "participants": [{"id": 1, "level": 10, "flags":4},{"id": 2, "level": 10, "flags":8}]}
{"queue-type": 2, "participants": [{"id": 3, "level": 10, "flags":0}]}
{"queue-type": 3, "participants": [{"id": 4, "level": 10, "flags":4},{"id": 5, "level": 10, "flags":8}]}
{"queue-type": 4, "participants": [{"id": 7, "level": 10, "flags":4},{"id": 8, "level": 10, "flags":8},{"id": 9, "level": 10, "flags":8}]}

我希望检索的结果:

db.queues.find({"participants.id": {"$in": [2]}});
{"queue-type": 1, "_matched": 2, "participants": [{"id": 1, "level": 10, "flags":4},{"id": 2, "level": 10, "flags":8}]}

注意&#34; _匹配&#34;元素与&#39; participant.id&#39;相同。在搜索查询上给出

另一个例子:

db.queues.find({"participants.id": {"$in": [2, 3, 6]}});
{"queue-type": 1, "_matched": 2, "participants": [{"id": 1, "level": 10, "flags":4},{"id": 2, "level": 10, "flags":8}]}
{"queue-type": 2, "_matched": 3, "participants": [{"id": 3, "level": 10, "flags":0}]}

多个匹配示例:

db.queues.find({"participants.id": {"$in": [1, 2, 3]}});
{"queue-type": 1, "_matched": 1, "participants": [{"id": 1, "level": 10, "flags":4},{"id": 2, "level": 10, "flags":8}]}
{"queue-type": 1, "_matched": 2, "participants": [{"id": 1, "level": 10, "flags":4},{"id": 2, "level": 10, "flags":8}]}
{"queue-type": 2, "_matched": 3, "participants": [{"id": 3, "level": 10, "flags":0}]}

一个不太好的解决方案就是简单地复制参与者&#39;数据(&#39;参与者-cpy&#39;)然后运行:

db.queues.find({"participants-cpy.id": {"$in": [2]}}, {"participants-cpy.$":1, "participants":1, "_id": 1, "queue-type":1})

可用于检索用于匹配&#39;的元素。查询,但这将生成重复的数据 - 这是非常糟糕的:p

1 个答案:

答案 0 :(得分:1)

常规find查询在此处不起作用。您需要使用聚合框架。在您的管道中,您需要使用$match管道运算符仅选择与您的查询条件匹配的文档。

管道中的下一个和最后一个阶段是$project阶段,您可以在其中将新字段“_matched”添加到文档中。如果你考虑一下,你会发现新字段只是一个数组,其中包含出现在“partcipantsId”数组/列表中的元素以及文档中“参与者”字段的所有“id”。

要获得该值,您只需使用$map$setIntersection运算符对participantId数组和“参与者”中的“id”数组执行集交集操作。请注意,结果数组仅包含唯一条目,因为$setIntersection会过滤掉重复项。

participantsId = [1, 2, 3]
db.queues.aggregate([
    { "$match": { "participants.id": { "$in": participantsId } } }, 
    { "$project": {
        "_matched": {
            "$setIntersection": [
                { "$map": { 
                    "input": "$participants", 
                    "as": "p", 
                    "in": "$$p.id"
                }}, 
                participantsId
            ]
        }, 
        "queue-type": 1, 
        "participants": 1
    }}
])