Das*_*uss 2 mongoose mongodb mongodb-query aggregation-framework
我有Orders 和Shops。
db={
"orders": [
{
"_id": 1,
"shop": 1,
"price": 11
},
{
"_id": 2,
"shop": 2,
"price": 101
},
],
"shops": [
{
"_id": 1,
},
{
"_id": 2,
},
{
"_id": 3,
},
],
}
Run Code Online (Sandbox Code Playgroud)
我想找出哪些商店的订单数为0。
我是这样做的
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
}
}
},
])
Run Code Online (Sandbox Code Playgroud)
这有效。我也尝试过其他几种方法。但它总是很贵!
如何更高效地找到0订单的店铺?有数千个订单和数千个商店,这需要很长时间。
正如您所提到的,当前的方法实际上$lookup只是在每个文档上使用,只是为了“不使用”结果,这里有明显的(巨大的)开销,并且可以很好地优化。
我会选择以下两种解决方案之一:
shop中的字段order不存在,则在该字段上创建索引。shop _ids现在首先从集合中获取所有内容,然后在集合上的查询order中使用它:findshopconst shopIds = await mongo.getCollection('orders').distinct('shop');
const shopsWithNoOrders = await mongo.getCollection('shops').find({ _id: {$nin: shopIds }});
Run Code Online (Sandbox Code Playgroud)
这种方法将比您当前的方法快得多,但是它确实存在一些问题,其中最大的问题是运算符$nin:
不等式运算符 $nin 的选择性不是很强,因为它通常匹配索引的很大一部分。因此,在许多情况下,带有索引的 $nin 查询的性能可能并不比必须扫描集合中所有文档的 $nin 查询好。另请参见查询选择性。
基本上性能还有待提高。
activeOrders”,本质上我们将在每个商店上维护一个计数器,用于显示当前有多少订单。这意味着对于每个订单插入和删除,您将需要更新商店的活动订单,这应该不会太难维护,并且是一种非常常见的访问模式,但是如果不了解您的应用程序,则很难保证这很容易实现。
一旦activeOrders维护了该字段,您就可以在其上构建索引并仅使用简单的查询:
const shopsWithNoOrders = await mongo.getCollection('shops').find({ activeOrders: 0 });
Run Code Online (Sandbox Code Playgroud)