具有多个条件的MongoDB查找管道无法过滤

时间:2020-10-19 16:22:10

标签: mongodb

我有两个收藏夹:

遥测:

{
    key: {
        serviceType: 3,
        serviceSubType: 4,
    },
    name: "ack",
    commandId: 3,
    params: [],
    groundTime: Date(...)
},
{
    key: {
        serviceType: 3,
        serviceSubType: 4,
    },
    name: "ack",
    params: [{ name: "commandId", value: 3 }],
    groundTime: Date(...)
},
{
    key: {
        serviceType: 4,
        serviceSubType: 5,
    },
    name: "other",
    params: [3],
    groundTime: Date(...)
}

电话命令:

{
    key: {
        serviceType: 3,
        serviceSubType: 4,
    },
    commandId: 3,
    params: [],
    sentTime: Date(...)
},
{
    key: {
        serviceType: 3,
        serviceSubType: 4,
    },
    commandId: 4,
    params: [],
    sentTime: Date(...)
}

我想对Telecommands集合进行查找:对于每个文档,请从Telemetry获取以下文档:

  1. 他们的name字段等于“ ack”
  2. 它们有一个commandId字段,并且与原始文档上的commandId相匹配 params数组中有一个子文档,其中的一个name字段等于“ commandId”,一个value字段等于原始文档中的commandId字段。

然后将它们放入“ acks”数组中:

{
    key: {
        serviceType: 3,
        serviceSubType: 4,
    },
    commandId: 3,
    params: [],
    sentTime: Date(...),
    acks: [{
                key: {
                    serviceType: 3,
                    serviceSubType: 4,
                },
                name: "ack",
                commandId: 3,
                params: [],
                groundTime: Date(...)
            },
            {
                key: {
                    serviceType: 3,
                    serviceSubType: 4,
                },
                name: "ack",
                params: [{ name: "commandId", value: 3 }],
                groundTime: Date(...)
            }]
},
{
    key: {
        serviceType: 3,
        serviceSubType: 4,
    },
    commandId: 4,
    params: [],
    sentTime: Date(...),
    acks: []
}

但是我做不到。

我尝试过:

$lookup: {
    from: "Telemetry",
    let: {
        commandId: "$telCommandId",
    },
    pipeline: [
        {
            $match: {
                name: "ack",
                $expr: {
                    $or: [
                        {
                            $eq: [
                                "$$commandId",
                                "$telCommandId"
                            ]
                        },
                        {
                            params: {
                                name: "commandId",
                                value: "$$commandId"
                            }
                        }
                    ]
                }
            }
        }
    ]
    as: "acks"
}

但是它不能正确过滤文档。

我该怎么办?

1 个答案:

答案 0 :(得分:1)

首先$lookup's let参数具有格式

let: { <var_1>: <expression>, …, <var_n>: <expression> },

var_1 ... var_n是管道参数中要使用的名称,expression分别为每个名称计算值。

您的

let: {
    commandId: "$telCommandId",
},

document.telCommandId的值分配给名为$$commandId的管道变量。至少对于您作为示例提供的文档,它总是null,因为那里没有这样的字段。

应该反过来:

let: {
    telCommandId: "$commandId",
},

以便$$telCommandId可以是3或4,具体取决于Telecommands集合中相应文档中document.commandId的值。

当然,您管道中的所有$$commandId都需要更改为$$telCommandId才能与let语句中的名称匹配。

下一步,当您测试

                    {
                        params: {
                            name: "commandId",
                            value: "$$commandId"
                        }
                    }

您正在过滤document.params等于

的文档
{
    name: "commandId",
    value: "$$commandId"
}

从字面上看。它不匹配任何内容,因为没有子文档的值等于字符串“ $$ commandId”。

您需要使用相同的$expr匹配器,用于将commandId与telCommandId进行比较。唯一的区别是,对于数组,您必须使用类似于$elemMatch的东西来比较同一元素的namevalue

相当于$ elemMatch的聚合可以是$size$filter的组合:

    {
      $gt: [
        {
          $size: {
            "$filter": {
              "input": "$params",
              "as": "p",
              "cond": {
                $and: [
                  {
                    $eq: [
                      "$$p.name",
                      "commandId"
                    ]
                  },
                  {
                    $eq: [
                      "$$p.value",
                      "$$telCommandId"
                    ]
                  },
                  
                ]
              }
            }
          }
        },
        0
      ]
    }