我有Order元和Shop元.

db={
  "orders": [
    {
      "_id": 1,
      "shop": 1,
      "price": 11
    },
    {
      "_id": 2,
      "shop": 2,
      "price": 101
    },
    
  ],
  "shops": [
    {
      "_id": 1,
      
    },
    {
      "_id": 2,
      
    },
    {
      "_id": 3,
      
    },
    
  ],
  
}

我想找出哪些store 没有订单.

我是这样做的

db.shops.aggregate([
  {
    $lookup: {
      from: "orders",
      let: {
        shop: "$_id"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $eq: [
                "$shop",
                "$$shop"
              ]
            },
            
          },
          
        },
        
      ],
      as: "orders",
      
    },
    
  },
  {
    $project: {
      user: "$user",
      orderCnt: {
        $size: "$orders"
      }
    }
  },
  {
    $match: {
      orderCnt: {
        $eq: 0
      }
    }
  },
  
])

这很管用.我还试过其他几种方法.但是它总是很贵的!

我如何才能更有效地找到订单为0的store ?由于有1000个订单和1000个store ,这需要很长的时间.

mongo playgound

推荐答案

正如您在当前方法中提到的,您基本上是在每个文档上使用$lookup,只是为了"不使用"结果,这存在明显的(巨大的)开销,这可以得到很好的优化.

我会从以下两种解决方案中 Select 一种:

  1. 如果order集合中的shop字段不存在,则创建一个索引(我建议少一些,但不需要进行预处理). 现在,首先从order集合中获取所有shop _ids,然后在对shop集合的find查询中使用它:
const shopIds = await mongo.getCollection('orders').distinct('shop');
const shopsWithNoOrders = await mongo.getCollection('shops').find({ _id: {$nin: shopIds }});

这种方法会比你目前的方法快得多,但它确实有一些问题,最大的问题是$nin运算符:

不等运算符 $nin 不是很有 Select 性,因为它通常与索引的很大一部分匹配.因此,在许多情况下, $nin 带有索引的查询的性能可能不会比 $nin 必须扫描集合中所有文档的查询.另请参阅查询 Select 性.

基本上,性能仍有改进的空间.

  1. 我推荐的解决方案需要一些预处理,这需要更改store 模式并添加一个新的字段"activeOrders",基本上我们将在每个store 上维护一个计数器,以确定它目前有多少订单.

这意味着对于每个订单的插入和删除,您将需要更新store 的活动订单,这应该不会太难维护,这是一个非常常见的访问模式,但如果不知道您的应用程序,很难保证这将很容易实现.

一旦您维护了activeOrders字段,您就可以在其上建立索引,只需使用一个简单的查询:

const shopsWithNoOrders = await mongo.getCollection('shops').find({ activeOrders: 0 });

Mongodb相关问答推荐

如何使用MongoDB对子文档进行条件投影?

Mongo Aggregate管道-另一个集合中的多个查找

MongoDB聚合$group阶段$top与$first在大型数据集上的效率

MongoDB $lookup 查找字段值数组

mongo如何通过聚合加载嵌套文档

分组前的 MongoDb 聚合总数

来自嵌套对象数组的 MongoDB 聚合

MongoDB 使用 pymongo 收集 500K 文档的写入速度很差

Mongo:查找具有 0 个关联文档的文档,成本更低

在数据中只有月份和年份的 mongodb 中字符串的日期时间

mongo.lock 文件有什么用?

如何将查询结果(单个文档)存储到变量中?

.NET 4 中是否有 mongodb C# 驱动程序支持 System.Dynamic.DynamicObject?

Mongoose.js 通过一个 connect() 调用创建到 MongoDB 的多个连接

有没有办法自动更新 MongoDB 中的两个集合?

如何使用node.js http服务器从mongodb返回大量行?

$orderby 和 Sort 之间的 MongoDB 区别

Meteor订阅不更新集合的排序顺序

如何向 mongodb 2.6 添加身份验证?

停止副本集 MongoDB