聚合管道中的Mongo“ $ cursor阶段中的错误...”

时间:2020-06-25 21:46:29

标签: arrays mongodb mongodb-query aggregation-framework lookup

我有订单

{_id: ObjectId("5e32d0fadf54cb3d81293fb3"),
user_id:'test_user',
product_id:'product_2_id'
created_at:'2020-02-25T07:04:05.439+00:00'
}

我需要加入 recommendedProducts 集合,该集合具有 orders.user_id 作为公用密钥,而 recommendedProducts.userId 类似于< / p>

{_id: ObjectId("5e3ac145df54cbeca6230924"),
userId:'test_user'
rankedList:[
0:{Name:'Product_4',id:'product_4_id'},
1:{Name:'Product_1',id:'product_1_id'},
2:{Name:'Product_2',id:'product_2_id'}],
Date:'2020-02-25T06:03:55.439+00:00'
}

{_id: ObjectId("5e388da4df54cb8efb47e61b"),
userId:'test_user'
rankedList:[
0:{Name:'Product_5',id:'product_5_id'},
1:{Name:'Product_6',id:'product_6_id'},
2:{Name:'Product_3',id:'product_3_id'}],
Date:'2020-02-25T05:03:55.439+00:00'
}

我已经阅读了this以及thisthat的帖子,但是我仍然无法弄清应该如何正确编写聚合管道。到目前为止,我有以下内容

db.orders.aggregate([
 {
    $lookup: {
        "from": "recommendedProducts",
        "as": "recommendations",
        "let": {
            "id": "$user_id"
        },
        "pipeline": [{
                "$match": {
                    "$expr": {
                        "$eq": ["$userId", "$$id"]
                    }
                }
            },
            {
                "$sort": {
                    "Date": -1
                }
            },
            {
                "$limit": 1
            }
        ]
    }
}
])

应该可以正常运行,但不会成功。 我需要在这里保留的是collectionProductsProducts集合中的最后一个文档,并且那里只有一个文档,这就是为什么我也使用sort和limit,但是却收到错误“ $ cursor stage错误::的原因: :操作超出了时间限制” 错误在哪里?

1 个答案:

答案 0 :(得分:3)

在使用$lookuplet形式的pipeline时,以及在使用$expr时,查询计划器当前都无法有效地使用索引

这意味着对于每个订单,查找阶段都在扫描整个RecommendationProducts集合以查找匹配的文档。

如果您要使用其他形式的查找,并且在RecommendationProducts集合中的userId字段上具有索引,则可以使用该索引更快地找到匹配的产品,然后可以使用展开,排序和分组,或者只是减少以获取最新值。

db.orders.aggregate([
 {
    $lookup: {
        "from": "recommendedProducts",
        "as": "recommendations",
        "localField": "user_id",
        "foreignField": "userId"
 },
 {$addFields: {
   recommendations:{ 
        $reduce: {
            input: "$recommendations",
            initialValue: {$arrayElemAt:["$recommendations",0]},
            in: {
               $cond: {
                    if: {$gt:["$$this.Date","$$value.Date"]},
                    then: "$$this",
                    else: "$$value"
                }
            }
        }
   }
 }}
])