基于匹配查询和优先级值的MongoDB聚合查询返回文档

时间:2020-04-07 14:09:43

标签: mongodb mongodb-query

在mongodb集合中,我有以下文档:

{"id":"1234","name":"John","stateCode":"CA"}
{"id":"1234","name":"Smith","stateCode":"CA"}
{"id":"1234","name":"Tony","stateCode":"GA"}
{"id":"3323", "name":"Neo","stateCode":"OH"}
{"id":"3323", "name":"Sam","stateCode":"US"}
{"id":"4343","name":"Bruce","stateCode":"NV"}

我正在尝试编写一个mongo聚合查询,该查询执行以下操作:

  • 基于id字段的匹配

  • 赋予stateCode字段中具有“ NV”或“ GA”以外的值的文档优先级。

    如果所有文档的值均为“ NV”或“ GA”,则忽略优先级。 如果任何文档中的{NV}或“ GA”以外的还有stateCode,则返回这些文档。

示例1:

id = "1234"

then return 

{"id":"1234","name":"John","stateCode":"CA"}
{"id":"1234","name":"Smith","stateCode":"CA"}

示例2:

id = "4343"

then return

{"id":"4343","name":"Bruce","stateCode":"NV"}

请帮助查询以实现此目标。

我尝试执行查询,但遇到错误:

Failed to execute script.

Error: command failed: {
    "ok" : 0,
    "errmsg" : "input to $filter must be an array not string",
    "code" : 28651,
    "codeName" : "Location28651"
} : aggregate failed

查询:

db.getCollection('emp').aggregate([{$match:{
            'id': "1234"
        }
},
{
      $project: {
         "data": {
            $filter: {
               input: "$stateCode",
               as: "data",
               cond: { $ne: [ "$data", "GA" ],$ne: [ "$data", "NV" ] }
            }
         }
      }
   }

])

1 个答案:

答案 0 :(得分:2)

我实际上建议您将其分为2个查询,首先尝试查找状态码不同的文档,如果失败,则检索其余文档。

这是一个可以一次性完成的工作流水线,由于我们无法事先知道条件是否成立,因此我们需要迭代所有与id匹配的文档,在许多文档共享id的情况下,这一事实非常低效,如果不可能,那么使用此管道就可以了。

db.getCollection('emp').aggregate([
    {
        $match: {
            'id': "1234"
        }
    },
    {   //we have to group so we can check
        $group: {
            _id: null,
            docs: {$push: "$$ROOT"}
        }
    },
    {
        $addFields: {
            highPriorityDocs: {
                $filter: {
                    input: "$docs",
                    as: "doc",
                    cond: {$and: [{$ne: ["$$doc.stateCode", "NV"]}, {$ne: ["$$doc.stateCode", "GA"]}]}
                }

            }
        }
    },
    {
        $project: {
            finalDocs: {
                $cond: [ // if size of high priority docs gt 0 return them.
                    {$gt: [{$ize: "$highPriorityDocs"}, 0]},
                    "$highPriorityDocs",
                    "$docs"
                ]
            }
        }
    },
    {
        $unwind: "$finalDocs"
    },
    {
        $replaceRoot: {newRoot: "$finalDocs"}
    }
])

最后两个阶段只是恢复原始结构,如果您不关心它,可以将其删除。

相关问题