【问题标题】:Mongoose - How to group by and populate?Mongoose - 如何分组和填充?
【发布时间】:2014-10-03 13:23:40
【问题描述】:

我使用 MongoDB 和 Mongoose 作为我的 ODM,并尝试在同一语句中使用 populategroup by 进行查询。

这是我的简单文档模型:

var userSchema = new Schema({
    username: String
});

var messageSchema = new Schema({
    from: { type: Schema.ObjectId, ref: 'User' },
    to: { type: Schema.ObjectId, ref: 'User' },
    message: String,
    date: { type: Date, default: Date.now }
});

我只是想为一个用户获取每条消息,按他与之交谈的每个用户分组。我试过这样:

this.find({ 'to': user })
    .sort({ 'date': 1 })
    .group('from')
    .populate(['from', 'to'])
    .exec(callback);

但是,不幸的是,我的模型没有group 方法。你有什么解决方案,让这个工作?

谢谢。

【问题讨论】:

    标签: javascript node.js mongodb mongoose aggregation-framework


    【解决方案1】:

    使用 $lookup 填充的示例,lookup 填充为数组,因此 $unwind。

    Message.aggregate(
        [
            { "$match": { "to": user } },
            { "$sort": { "date": 1 } },
            { "$group": { 
                "_id": "from",
                "to": { "$first": "$to" },
                "message": { "$first": "$message" },
                "date": { "$first": "$date" },
                "origId": { "$first": "$_id" }
            }},
            { "$lookup": {
                 "from": "users",
                 "localField": "from",
                 "foreignField": "_id",
                 "as": "from"
            }},
            { "$lookup": {
                 "from": "users",
                 "localField": "to",
                 "foreignField": "_id",
                 "as": "to"
            }},
            { "$unwind": { "path" : "$from" } },
            { "$unwind": { "path" : "$to" } }
        ],
        function(err,results) {
            if (err) throw err;
            return results;
        }
    )
    

    【讨论】:

    • 很好,但是select 怎么可能只是填充文档中的一些字段?
    • 您可以使用 $project 运算符选择最后返回的字段,{$project: { from: 1, to: 1, message: 1} } 我猜您的模型包含的数据比问题中描述的要多?
    【解决方案2】:

    这里使用的更好的选择是.aggregate(),它是一种原生代码实现,不同于MongoDB 的.group() 方法,它使用JavaScript 引擎来处理结果。

    .populate() 之类的方法虽然不受直接支持,但这是设计使然,因为聚合管道和其他方法不会严格返回基于当前模型架构的响应。由于“假设”这是您正在做的事情是错误的,因此它只是一个原始对象响应。

    然而,没有什么能阻止您将响应“转换”为 mongoose 文档,然后使用所需路径调用 .populate() 的模型形式:

    Message.aggregate(
        [
            { "$match": { "to": user } },
            { "$sort": { "date": 1 } },
            { "$group": { 
                "_id": "from",
                "to": { "$first": "$to" },
                "message": { "$first": "$message" },
                "date": { "$first": "$date" },
                "origId": { "$first": "$_id" }
            }}
        ],
        function(err,results) {
            if (err) throw err;
            results = result.map(function(doc) { 
                doc.from = doc._id
                doc._id = doc.origId;
                delete doc.origId;
                return new Message( doc ) 
            });
            User.populate( results, { "path": "from to" }, function(err,results) {
                if (err) throw err;
                console.log( JSON.stringify( results, undefined, 4 ) );
            });
        }
    )
    

    当然,这只是真正地从每个“来自”返回 $first 消息,正如操作员所暗示的那样。

    也许您所说的“分组依据”实际上是“排序”:

    Message.find({ "to": user })
        .sort({ "from": 1, "date": 1 })
        .populate("from to")
        .exec(function(err,messsages) {
            if (err) throw err;
            console.log( JSON.stringify( messages, undefined, 4 ) );
        });
    

    正如您的上下文所说的“所有消息”,而不是诸如 .aggregate().group() 集合方法之类的分组运算符所暗示的内容。因此,消息通过排序“组合在一起”,而不是任何特定的分组。

    后者听起来像你真正要问的,但如果你真的想要真正的“分组”,那么这里有聚合示例以及如何使用.populate()

    【讨论】:

    • 你能提供一个查询来聚合和填充吗?
    【解决方案3】:

    这就是我按单位类型对单位进行分组的方式

    分组前

    [
    {
        "_id": "5f68d604d47d3517ac3f00a1",
        "active": true,
        "unitName": "3",
        "unitType": [
            {
                "_id": "5f5b0a20c546f803d36f43b2",
                "active": true,
                "facilities": [
                    "5f5b0977c546f803d36f43b0",
                    "5f5b096ac546f803d36f43ae"
                ],
                "typeName": "Deluxe Room",
                "numberOfBeds": 2,
                "rate": 15000,
                "__v": 0
            }
        ],
        "status": "CLEANING",
        "createdAt": "2020-09-21T16:34:12.189Z",
        "__v": 0
    },
    {
        "_id": "5f6adb612bf2c33614d9d28e",
        "active": true,
        "unitName": "1",
        "unitType": [
            {
                "_id": "5f5b0a20c546f803d36f43b2",
                "active": true,
                "facilities": [
                    "5f5b0977c546f803d36f43b0",
                    "5f5b096ac546f803d36f43ae"
                ],
                "typeName": "Deluxe Room",
                "numberOfBeds": 2,
                "rate": 15000,
                "__v": 0
            }
        ],
        "status": "READY",
        "createdAt": "2020-09-23T05:21:37.746Z",
        "__v": 0
    }]
    

    聚合中

    Unit.aggregate([
        {
            $match:{
                _id : {
                    $nin : reservedUnits
                }
            }
        },
        {
            $lookup: {
                from: 'unittypes',
                localField: 'unitType',
                foreignField: '_id',
                as: 'unitType'
            }
        },
        {
            $project: {
                unitType: {
                    createdAt: 0
                }
            }
        },
        {$group : {_id : "$unitType", units: { $push: "$$ROOT" }}},
        {
            $project: {
                _id : {
                    facilities: 0
                },
                units: {
                    unitType: 0
                }
            }
        },
    ]);
    

    结果

    [
    {
        "_id": [
            {
                "_id": "5f5b0a20c546f803d36f43b2",
                "active": true,
                "typeName": "Deluxe Room",
                "numberOfBeds": 2,
                "rate": 15000,
                "__v": 0
            }
        ],
        "units": [
            {
                "_id": "5f68d604d47d3517ac3f00a1",
                "active": true,
                "unitName": "3",
                "status": "CLEANING",
                "createdAt": "2020-09-21T16:34:12.189Z",
                "__v": 0
            },
            {
                "_id": "5f6adb612bf2c33614d9d28e",
                "active": true,
                "unitName": "1",
                "status": "READY",
                "createdAt": "2020-09-23T05:21:37.746Z",
                "__v": 0
            }
        ]
    }]
    

    【讨论】:

      猜你喜欢
      • 2019-01-31
      • 2014-12-05
      • 2019-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-01
      • 2016-03-01
      • 1970-01-01
      相关资源
      最近更新 更多