MongoDb$elemMatch和$lookup变量

MongoDb$elemMatch和$lookup变量,mongodb,query-optimization,Mongodb,Query Optimization,我有一个给定的MongoDb集合,其中的文档与以下内容类似: { items: [ { id: 1, data: 'a' }, { id: 2, data: 'b' }, { id: 3, data: 'c' }, ] } 现在我必须从这个集合中$lookup。我需要id=2的元素中的数组数据,其中id=1的数据与查找值$$value匹配。我第一次天真地尝试找到正确的文档如下所示: $match { items: { $elemMatch: { id: 1, d

我有一个给定的MongoDb集合,其中的文档与以下内容类似:

{
items: [
  { id: 1, data: 'a' },
  { id: 2, data: 'b' },
  { id: 3, data: 'c' },
]
}
现在我必须从这个集合中
$lookup
。我需要id=2的元素中的数组数据,其中id=1的数据与查找值
$$value
匹配。我第一次天真地尝试找到正确的文档如下所示:

$match {
  items: { $elemMatch: {
    id: 1,
    data: '$$value'
  } }
}
但是,
$$value
不会被计算,因此数据将与文本而不是其值进行比较。我还尝试使用
$expr
计算该值,但无法获得正确的语法(如果可能的话)

我能够开始工作的唯一工作方式是先提取数据,然后进行匹配:

[
    {
        $project: {
            _id: 0,
            data1: {
                $filter: {
                    input: '$items', as: 'item',
                    cond: {$eq: ['$$item.id', 1]}
                }
            },
            data2: {
                $filter: {
                    input: '$items', as: 'item',
                    cond: {$eq: ['$$item.id', 2]}
                }
            },
        }
    },
    {
        $set: {
            data1: {$arrayElemAt: ['$data1.data', 0]},
            data2: {$arrayElemAt: ['$data2.data', 0]}
        }
    },
    {
        $match: {
            $expr: {$eq: ['$data1', '$$value']}
        }
    }
];
但正如人们所料,这种方法要慢得多。对于所涉及的数据,查询耗时7秒,而上层方法(使用常量而不是变量
$$value
)的速度则快了3倍


是否可以在
$elemMatch
运算符中直接使用变量
$$value
?或者是否有任何其他优化可用于加快集合查找?

因此,首先让我们了解为什么您的天真方法失败,Mongo的文档指定:

$match阶段需要使用$expr运算符来访问变量$expr允许在$match语法中使用聚合表达式

因此,您在
$lookup
开头定义的变量
只能通过使用来访问,现在也在
$expr
文档中指定:

参数可以是任何有效的聚合表达式

遗憾的是,它不是一个“聚合表达式”,因为它属于“查询语言”。这就是为什么你的第一个方法失败了。您不允许在访问
$$value
字段所需的
$expr
中使用
$elemMatch

那么我们能做什么呢?好吧,你可以像你已经开始做的那样使用:

db.collection.aggregate([
  {
    $lookup: {
      from: "collection2",
      let: {
        value: "$data"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $gt: [
                {
                  $size: {
                    $filter: {
                      input: "$items",
                      as: "item",
                      cond: {
                        $and: [
                          {
                            $eq: [
                              "$$item.id",
                              1
                            ]
                          },
                          {
                            $eq: [
                              "$$item.data",
                              "$$value"
                            ]
                          }
                        ]
                      }
                    }
                  }
                },
                0
              ],
              
            }
          }
        }
      ],
      as: "res"
    }
  }
])
如果您提供集合的完整结构和所需的最终结果,那么完整的回答就更容易了,因为为了编写这个管道,我不得不在这里猜测一些内容


谢谢您的详细解释。你的演示结构足以满足我的需要。如果可以,我会给Mongo游乐场链接另一个+1!不幸的是,我基于您的解决方案更新的查询比我的第一种方法慢…没问题,常量值总是最有效的,因为它不需要任何结构操作使用,如
$filter