【问题标题】:How to get the objects inside an array of objects which is inside an document in mongoose/mongodb?如何在 mongoose/mongodb 的文档中获取对象数组中的对象?
【发布时间】:2015-05-05 21:39:36
【问题描述】:

这是文档的结构。

{
    "_id" : ObjectId("5548b2b79b9567341c77d352"),
    "messages" : [
        {
            "subject" : "fresh subject ",
            "from" : ObjectId("5534b2992a104ed914435c31"),
            "_id" : ObjectId("5548b5dab9279faf1c1b8688"),
            "created" : ISODate("2015-05-05T12:21:46.261Z"),
            "read" : true,
            "message" : "fresh message ",
            "participants" : [
                ObjectId("5534b2992a104ed914435c31"), //logged in user
                ObjectId("5530af38576214dd3553331c")
            ]
        },
        {
            "subject" : " subjet",
            "from" : ObjectId("5530af38576214dd3553331c"),
            "_id" : ObjectId("5548b608b9279faf1c1b8689"),
            "created" : ISODate("2015-05-05T12:22:32.809Z"),
            "read" : true,
            "message" : "is fresh?",
            "participants" : [
                ObjectId("5530af38576214dd3553331c")
            ]
        }
    ],
    "participants" : [
        ObjectId("5534b2992a104ed914435c31"),
        ObjectId("5530af38576214dd3553331c")
    ],
    "__v" : 2
}

在一个特定对象的消息数组中有几个对象。只有当该对象的参与者数组包含登录用户时,我才想获取消息数组中的对象。

我有文档的对象 ID (5548b2b79b9567341c77d352) 和登录的用户 ID (5534b2992a104ed914435c31)。 如何在猫鼬中做同样的事情?

【问题讨论】:

    标签: arrays node.js mongodb mongoose


    【解决方案1】:

    您可以使用 MongoDB 的 aggregation framework 来获得所需的结果。聚合管道将包含一个初始步骤,该步骤具有一个 $match 运算符,该运算符根据上述标准过滤文档。下一个管道阶段将是 $unwind 运算符,它从输入文档解构消息数组以输出每个元素的文档。另一个$match 过滤器然后仅返回具有参与者ID 的文档。 $project 运算符的最后一步然后将仅包含指定字段的文档传递给结果:

    db.collection.aggregate([
        {
            "$match": {
                "_id" : ObjectId("5548b2b79b9567341c77d352"),
                "messages.participants": ObjectId("5534b2992a104ed914435c31")
            }
        },
        {
            "$unwind": "$messages"
        },
        {
            "$match": {            
                "messages.participants": ObjectId("5534b2992a104ed914435c31")
            }
        },
        {
            "$project": {
                "_id": 0,
                "messages": 1
            }
        }
    
    ])
    

    结果:

    /* 0 */
    {
        "result" : [ 
            {
                "messages" : {
                    "subject" : "fresh subject ",
                    "from" : ObjectId("5534b2992a104ed914435c31"),
                    "_id" : ObjectId("5548b5dab9279faf1c1b8688"),
                    "created" : ISODate("2015-05-05T12:21:46.261Z"),
                    "read" : true,
                    "message" : "fresh message ",
                    "participants" : [ 
                        ObjectId("5534b2992a104ed914435c31"), 
                        ObjectId("5530af38576214dd3553331c")
                    ]
                }
            }
        ],
        "ok" : 1
    }
    

    在 Mongoose 中,您可以使用相同的 aggregation 管道,如下所示:

    // Using the pipeline builder
    Model.aggregate({
            "$match: {
                ""_id" : ObjectId("5548b2b79b9567341c77d352"),
                "messages.participants": ObjectId("5534b2992a104ed914435c31")
            }
        })
        .unwind("messages")
        .match({ "messages.participants": ObjectId("5534b2992a104ed914435c31") })
        .project({
            "_id": 0,
            "messages": 1
        })
        .exec(function (err, res) {
            if (err) return handleError(err);
            console.log(res); 
        });
    
    // Or the simple aggregate method
    var pipeline = [
        {
            "$match": {
                "_id" : ObjectId("5548b2b79b9567341c77d352"),
                "messages.participants": ObjectId("5534b2992a104ed914435c31")
            }
        },
        {
            "$unwind": "$messages"
        },
        {
            "$match": {            
                "messages.participants": ObjectId("5534b2992a104ed914435c31")
            }
        },
        {
            "$project": {
                "_id": 0,
                "messages": 1
            }
        }
    
    ]
    
    Model.aggregate(pipeline, function (err, res) {
        if (err) return handleError(err);
        console.log(res); 
    });
    

    【讨论】:

    • 但我还想填充“来自”和“参与者”字段。当我尝试使用填充时,它显示以下错误。对象 # 没有方法 'populate'
    • @SachinKalsi 你从来没有提到在你的问题中填充from 和participants 字段。该解决方案直接解决了您在问题中提出的问题。您不能使用带有 Mongoose 聚合方法的填充。在聚合框架中,返回的字段由您构建,您可以“重命名”文档属性,这意味着 Mongoose 无法确定您引用的文档将在最终结果中可用。
    【解决方案2】:

    除了聚合框架之外的另一个解决方案是使用$elemMatch 投影运算符。

    例如:

    var id = '5548b2b79b9567341c77d352';
    var loggedInUserId = '5534b2992a104ed914435c31';
    var projection = {
        participants: 1,
        messages: {
            $elemMatch: { participants: new ObjectId(loggedInUserId) }
        }
    };
    
    Model.findById(id, projection, function(err, result) {
        console.log(result);
    });
    

    这将输出:

    { _id: 5548b2b79b9567341c77d352,
      participants: [ 5534b2992a104ed914435c31, 5530af38576214dd3553331c ],
      messages: 
       [ { participants: [Object],
           message: 'fresh message ',
           read: true,
           created: Tue May 05 2015 09:21:46 GMT-0300 (BRT),
           _id: 5548b5dab9279faf1c1b8688,
           from: 5534b2992a104ed914435c31,
           subject: 'fresh subject ' } ] }
    

    【讨论】:

      【解决方案3】:

      您可以使用 Aggregation Framework 到 $unwind 子文档数组(将它们拆分为您可以匹配的自己的文档。我将使用的查询:

      .aggregate([
          {$unwind: "$messages"},
          {$match:
              {"messages.participants": ObjectId("5534b2992a104ed914435c31")}
          }
      ])
      

      这将为与该参与者匹配的每个 message 子文档在结果集中返回一个单独的 message 文档。

      使用 Mongoose 构造,这看起来像:

      Conversation
          .aggregate({$unwind: "messages"})
          .match({
              "messages.participants": mongoose.Types.ObjectId("5534b2992a104ed914435c31")
          })
          .exec(cb);
      

      第一个$match不是绝对必要的,但是

      【讨论】:

      • 但我还想填充“来自”和“参与者”字段。当我尝试使用填充时,它显示以下错误。对象 # 没有方法 'populate'
      • @SachinKalsi from 和 participants 应该已经在结果中
      猜你喜欢
      • 1970-01-01
      • 2016-01-23
      • 2021-11-16
      • 2018-05-25
      • 1970-01-01
      • 2021-12-29
      • 2020-06-13
      • 2018-06-12
      • 2022-01-21
      相关资源
      最近更新 更多