MongoDB:根据$或值的顺序查找一个文档?

时间:2015-06-01 02:55:30

标签: mongodb

findOne()

  

如果多个文档满足查询,则此方法根据反映磁盘上文档顺序的自然顺序返回第一个文档。

我需要与上面类似的效果,除非多个文档满足查询,它返回最早出现在$或数组中的文档。

db.collection.findOne({
     $or: [
         {"apple": "blah"},
         {"orange": "blah"},
         {"grape": "blah"}
     ]
})

例如,如果这些文件都满足上述查询

[
    {"apple": "....", "orange": "....", "grape": "blah"},
    {"apple": "....", "orange": "blah", "grape": "...."}
]

它只会返回与orange匹配的文档(上面的第二个),因为orange位于$或数组中的grape之前。同样,如果文档与apple匹配,则会返回该文档,因为apple在数组中较早出现。怎么办呢?

1 个答案:

答案 0 :(得分:4)

听起来你基本上想要为每个文档分配一个“得分”,然后只返回一个“得分最高”的文档。一种方法是使用aggregation framework并在初始查询中添加$project$sort阶段。然后你$limit得到第一个或“最高”分数的结果:

db.collection.aggregate([
    { "$match": {
        "$or": [
            { "apple": "blah" },
            { "orange": "blah" },
            { "grape": "blah" }
        ]
    }},
    { "$project": {
        "apple": 1,
        "orange": 1,
        "grape": 1,
        "score": {
            "$add": [
                { "$cond": [{ "$eq": [ "$apple", "blah" ] }, 5, 0 ] },
                { "$cond": [{ "$eq": [ "$orange", "blah" ] }, 3, 0 ] },
                { "$cond": [{ "$eq": [ "$grape", "blah" ] }, 1, 0 ] }
            ]
        }
    }},
    { "$sort": { "score": -1 } },
    { "$limit": 1 }
])

这基本上为您提供了与您查询的项目“最佳匹配”的单一结果。或多或少具有计算字段的.findOne()操作。