【问题标题】:Moongoose aggregate $match does not match id'sMongoose 聚合 $match 不匹配 id
【发布时间】:2016-07-11 15:16:22
【问题描述】:

我想按 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)

这是我的查询

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)
        }
    })

如果我添加这个$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)
        }
    })

【问题讨论】:

    标签: mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    您的 ids 变量将由“字符串”而不是 ObjectId 值构成。

    Mongoose 将 ObjectId 的字符串值“自动转换”为常规查询中的正确类型,但这是 does not happen in the aggregation pipeline,如问题 #1399 中所述。

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

    ids = ids.map(function(el) { return mongoose.Types.ObjectId(el) })
    

    然后你可以在你的流水线阶段使用它们:

    { "$match": { "_id": { "$in": ids } } }
    

    原因是因为聚合管道“通常”会改变文档结构,因此 mongoose 不会假定“模式”适用于任何给定管道阶段的文档。

    有争议的是,当它是$match 阶段时,“第一个”管道阶段应该这样做,因为确实文档没有改变。但现在情况并非如此。

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

    【讨论】:

    • 就是这样,它现在可以工作了。但通常我在 findOneAndUpdate 或其他查询中将 id 作为字符串抛出,它工作正常,问题只发生在聚合中吗?
    • @MuhammadFasalirRahman 这正是我的回答。 .find() 可以使用Schema,当然_id 字段的默认类型为ObjectId。正如我实际上已经解释的那样,聚合管道使用Schema
    • 我花了三天时间才到这里;叹息.. 我在我的模式静态方法 const castUserId = (userId) => mongoose.Types.ObjectId(userId) 中创建了一个 lamda,现在我很高兴
    • 大声笑......在这个问题上浪费了几个小时......感谢您的解决方案
    【解决方案2】:
    1. 在 mongoose 中,find({_id:'606c1ceb362b366a841171dc'}) 可以正常工作

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

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

    这会很好用。

    【讨论】:

      【解决方案3】:

      您可以简单地将您的 id 转换为

       let id = mongoose.Types.ObjectId(req.query.id);
      

      然后匹配

       { $match: { _id: id } },
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-16
        • 1970-01-01
        相关资源
        最近更新 更多