Moongoose聚合$ match与id不匹配

Muh*_*man 18 mongoose mongodb mongodb-query aggregation-framework

我希望按ID(56e641d4864e5b780bb992c656e65504a323ee0812e511f2)显示产品,并在扣除减价后显示价格(如果有).

我可以使用聚合计算最终价格,但这会返回集合中的所有文档,如何使其仅返回匹配ID

"_id" : ObjectId("56e641d4864e5b780bb992c6"), 
"title" : "Keyboard", 
"discount" : NumberInt(10),
"price" : NumberInt(1000)

"_id" : ObjectId("56e65504a323ee0812e511f2"), 
"title" : "Mouse", 
"discount" : NumberInt(0),
"price" : NumberInt(1000)

"_id" : ObjectId("56d90714a48d2eb40cc601a5"), 
"title" : "Speaker", 
"discount" : NumberInt(10),
"price" : NumberInt(1000)
Run Code Online (Sandbox Code Playgroud)

这是我的疑问

productModel.aggregate([
        {
            $project: {
                title   : 1,
                price: {
                    $cond: {
                        if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
                    }

                }
            }
        }
    ], function(err, docs){
        if (err){
            console.log(err)
        }else{
            console.log(docs)
        }
    })
Run Code Online (Sandbox Code Playgroud)

如果我添加此$in查询,它将返回空数组

productModel.aggregate([
            {
                $match: {_id: {$in: ids}}
            },
            {
                $project: {
                    title   : 1,
                    price: {
                        $cond: {
                            if: {$gt: ["$discount", 0]}, then: {$subtract: ["$price", {$divide: [{$multiply: ["$price", "$discount"]}, 100]}]}, else: "$price"
                    }

                }
            }
        }
    ], function(err, docs){
        if (err){
            console.log(err)
        }else{
            console.log(docs)
        }
    })
Run Code Online (Sandbox Code Playgroud)

Bla*_*ven 40

您的ids变量将由"字符串"构成,而不是ObjectId值.

Mongoose ObjectId在自定义查询中"自动"将字符串值转换为正确的类型,但这不会发生在聚合管道中,如问题#1399中所述.

相反,您必须执行正确的转换才能手动输入:

ids = ids.map(function(el) { return mongoose.Types.ObjectId(el) })
Run Code Online (Sandbox Code Playgroud)

然后,您可以在管道阶段使用它们:

{ "$match": { "_id": { "$in": ids } } }
Run Code Online (Sandbox Code Playgroud)

原因是因为聚合管道"通常"会改变文档结构,因此猫鼬没有假设"模式"适用于任何给定管道阶段的文档.

有争议的是,当它处于一个阶段时,"第一"流水线阶段$match应该这样做,因为确实文件没有改变.但是现在这不是它发生的方式.

任何可能是"字符串"或至少不是正确的BSON类型的值都需要手动转换才能匹配.

  • 我花了三天时间才到这里;叹气..我在我的架构静态方法`const castUserId = (userId) => mongoose.Types.ObjectId(userId)`中创建了一个lamda,现在我很高兴 (2认同)
  • 哈哈...在这个问题上浪费了几个小时...感谢您的解决方案 (2认同)

小智 18

  1. 在 mongoose 中,它与 find({_id:'606c1ceb362b366a841171dc'}) 配合得很好

  2. 但是在使用聚合函数时,我们必须使用 mongoose 对象将 _id 转换为对象,例如。

$match: { "_id": mongoose.Types.ObjectId("606c1ceb362b366a841171dc") }

这会工作得很好。


Seh*_*eed 9

您只需将您的 id 转换为

 let id = mongoose.Types.ObjectId(req.query.id);
Run Code Online (Sandbox Code Playgroud)

然后匹配

 { $match: { _id: id } },
Run Code Online (Sandbox Code Playgroud)