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

Returning the matched element from a $in query

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

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

请注意“_matched”元素与搜索查询中给出的 'participant.id' 相同

另一个例子:

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}]}

一个不好的解决方案是简单地复制 'participants' 数据 ('participants-cpy') 然后 运行:

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

可用于检索用于 'match' 查询的元素,但这会生成重复数据 - 这非常糟糕 :p

常规 find query will not work here. You need to use the aggregation framework. In your pipeline you need to select only those documents that match your query criteria using the $match 管道操作员。

管道中的下一个也是最后一个阶段是 $project 阶段,您可以在该阶段将新字段“_matched”添加到文档中。如果您考虑一下,您会意识到新字段只不过是一个数组,其中包含出现在 "partcipantsId" array/list 和 [=28] 中的所有 "id" 中的元素=] 文档中的字段。

要获得该值,您只需使用 $map and the $setIntersection 运算符对来自 "participants" 的 participantsId 数组和 "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
    }}
])