如何在mongoose / mongodb中的文档内部获取对象数组?

时间:2015-05-05 12:52:58

标签: arrays node.js mongodb mongoose

这是文件的结构。

{
    "_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
}

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

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

3 个答案:

答案 0 :(得分:2)

您可以使用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); 
});

答案 1 :(得分:1)

除了聚合框架之外的另一个解决方案是使用$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 ' } ] }

答案 2 :(得分:0)

您可以使用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并非绝对必要,但