MongoDB:嵌套$并且不起作用

问题描述 投票:0回答:2

问题

假设我们有三个文件:

[
  {
    row: [
      {identifier: 'a', value: 10},
      {identifier: 'b', value: 24},
      {identifier: 'c', value: 3},
    ]
  },
  {
    row: [
      {identifier: 'a', value: 11},
      {identifier: 'b', value: 75},
      {identifier: 'c', value: 4},
    ]
  },
  {
    row: [
      {identifier: 'a', value: 2},
      {identifier: 'b', value: 1},
      {identifier: 'c', value: 3},
    ]
  }
]

预期结果

如果不满足任何条件,则每行的值应为null。条件必须包括identifier。这对我来说是个问题。

[
  {
    row: [
      {identifier: 'a', value: null}, // Because it's 'a' and lower than 10
      {identifier: 'b', value: null}, // Because 'a' is lower than 10
      {identifier: 'c', value: null}  // Because 'a' is lower than 10
    ]
  },
  {
    row: [
      {identifier: 'a', value: 11}, // Because it's 'a' and not lower than 10
      {identifier: 'b', value: 75}, // Because 'a' or 'c' are not lower than 10, greater than 5
      {identifier: 'c', value: 4}   // Because it's 'c' and greater than 5
    ]
  }, 
  {
    row: [
      {identifier: 'a', value: null}, // Because it's 'a' and lower than 10
      {identifier: 'b', value: null}, // Because 'a' is lower than 10
      {identifier: 'c', value: null}  // Because 'a' is lower than 10
    ]
  }
]

方法#1

// ... Rest
$project: {
  row: {
    $cond: [
      {
        $eq: [
          {
            $size: {
              $filter: {
                input: '$row',
                as: 'row',
                cond: {
                  $and: [ // Using $or here produces an output
                    {
                      $and: [
                        {$eq: ['$$row.identifier', 'a']},
                        {$gt: ['$$row.value', 10]}
                      ],
                    },
                    {
                      $and: [
                        {$eq: ['$$row.identifier', 'b']},
                        {$lt: ['$$row.value', 5]}
                      ]
                    }  
                 ]
              }
            }
          },
          0
        ]
      },
      {
        $map: {
          input: '$row',
          as: 'row',
          in: {identifier: '$$row.identifier', value: null}
        }
      },
      '$row'
    ]
  }
}
// ... Rest

我以为MongoDB看到了这个:

(A AND B) AND (C AND D)

它首先评估括号,但事实并非如此。

方法#2

当我用$nor替换MongoDB时抛出:

MongoError:无法识别的表达式'$ nor'

当我将第一个$and更改为$or时,整个查询工作正常,但这不是我期望的结果。


更新

一个条件是正常工作:

$eq: [
  {
    $size: {
      $filter: {
        input: '$row',
        as: 'row',
        cond: {
          $or: [
            {
              $and: [
                {$eq: ['$$row.identifier', 'a']},
                {$gt: ['$$row.value', 10]}
              ]
            }
          ]
        }
      }
    }
  },
  0
]

现在所有行的值都变为null。如果我添加第二个条件,它会被反转($gt变成$lt)。我不明白为什么。

mongodb
2个回答
2
投票

您需要以下标准的预期输出。您还缺少$$引用,该引用用于引用在filter运算符中的as中创建的用户变量。

{
  "$or":[
    {"$and":[
      {"$eq":["$$row.identifier","a"]},{"$lte":["$$row.value",10]}
    ]},
    {"$and":[
      {"$eq":["$$row.identifier","b"]},{"$lt":["$$row.value",5]}
    ]}
  ]
}

1
投票

您可以使用$addFields创建临时字段,该字段将表示当前文档是使用($allElementsTrue)匹配所有条件,然后使用$map生成预期输出

db.col.aggregate([
    {
        $addFields: {
            matches: {
                $allElementsTrue: {
                    $map: {
                        input: "$row",
                        as: "r",
                        in: {
                           $switch: {
                              branches: [
                                 { case: { $and: [{$eq: ["$$r.identifier", "a"]},{$lte: ["$$r.value", 10] }] }, 
                                     then: false },
                                 { case: { $and: [{$eq: ["$$r.identifier", "b"]},{$gte: ["$$r.value", 5] }] }, 
                                     then: false },
                              ],
                              default: true
                           }
                        }
                    }
                }
            }
        }
    },
    {
        $project: {
            row: {
                $map: {
                    input: "$row",
                    as: "r",
                    in: {
                         $cond: { 
                            if: { $eq: [ "$matches", true ] }, 
                            then: "$$r", 
                            else: { identifier: "$$r.identifier", value: null } 
                        }
                    }
                }
            }
        }
    }
])
© www.soinside.com 2019 - 2024. All rights reserved.