【问题标题】:better way to limit properties of a field in aggregate call在聚合调用中限制字段属性的更好方法
【发布时间】:2018-05-17 12:59:24
【问题描述】:

所以我试图在 MongoDB 中执行 aggregate 调用来查找一个集合,但同时限制我从另一个集合中获得的数据量。这是我尝试的那种工作:

getFamilyStats: function (req, res) {
    Families
        .aggregate([
            { $match: { 'centralPath': req.body.centralPath }},
            { $lookup: {
                from: 'models',
                localField: 'centralPath',
                foreignField: 'centralPath',
                as: 'models'
            }},
            { $unwind: '$models'},
            { $project: {
                'models.openTimes.user': 1,
                '_id': 1,
                'centralPath': 1,
                'totalFamilies': 1,
                'unusedFamilies': 1,
                'oversizedFamilies': 1,
                'inPlaceFamilies': 1,
                'families': 1
            }}
            ]
        ).exec(function (err, response){
            var result = {
                status: 200,
                message: response
            };
            if (err){
                result.status = 500;
                result.message = err;
            } else if (!response){
                result.status = 404;
                result.message = err;
            }
            res.status(result.status).json(result.message);
        });
},

所以效果很好的是我可以使用lookup 来“加入”来自不同集合的数据,在这种情况下称为模型。一旦我unwind 它看起来就像我想要它,除了我只对该属性中的一个字段感兴趣:models.openTimes 并且在这种特殊情况下实际上只是该字段的一个属性user。我尝试使用project 来限制我从模型中传递的大部分数据,但这迫使我像这样拼出所有其他字段:

_id: 1,
centralPath: 1....

如果我的收藏随着新的属性而扩展,这并不理想。我正在寻找一种方法来将来自models 的数据限制为一个字段/一个属性,但从families 集合中获取所有字段。

想法?

家庭样本数据:

{
    "_id" : ObjectId("5ae08c75d132ac4442520672"),
    "centralPath" : "some path",
    "totalFamilies" : 0,
    "unusedFamilies" : 0,
    "oversizedFamilies" : 0,
    "inPlaceFamilies" : 0,
    "families" : [],
    "__v" : 0
}

模型的样本数据:

{
    "_id" : ObjectId("5ae08c74d132ac4442520638"),
    "centralPath" : "some path",
    "openTimes" : [ 
        {
            "value" : 8123,
            "user" : "ks",
            "createdOn" : ISODate("2018-04-25T14:11:00.853Z"),
            "_id" : ObjectId("5ae08c74d132ac444252063a")
        }
    ],
    "synchTimes" : [ 
        {
            "value" : 208649,
            "user" : "ks",
            "createdOn" : ISODate("2018-04-25T16:42:42.933Z"),
            "_id" : ObjectId("5ae0b0028c2e3b192a3e9dc5")
        }
    ],
    "modelSizes" : [ 
        {
            "value" : 21483520,
            "user" : "ks",
            "createdOn" : ISODate("2018-04-25T14:11:00.787Z"),
            "_id" : ObjectId("5ae08c74d132ac4442520639")
        }
    ],
    "__v" : 0
}

【问题讨论】:

    标签: javascript node.js mongodb mongoose


    【解决方案1】:

    从 MongoDB v3.6 开始,您可以直接限制 $lookup 返回的字段:

    db.families.aggregate([
        { $match: { 'centralPath': 'some path' } },
        { $lookup: {
            from: 'models',
            let: { centralPath: '$centralPath' }, // remember the value of the "centralPath" field
            pipeline: [
                { $match: { $expr: { $eq: [ '$centralPath',  '$$centralPath' ] } } }, // this performs the "join"
                { $project: { _id: 0, 'openTimes.user': 1 } } // only retrieve the "openTimes.user" field
            ],
            as: 'models'
        }},
        { $unwind: '$models'},
    ]);
    

    【讨论】:

    • 良好的描述和更好更短的选择来实现目标。为您的逻辑 +1 :)
    【解决方案2】:

    您可以在 3.4 及以上版本中尝试以下聚合。

    $addFields 返回加入集合中的唯一字段,同时保留现有字段,$project 排除加入集合数据。

    将项目阶段替换为 addFields 和项目阶段。

    Families.aggregate([
     existing stages,
      {"$addFields":{
        "user":"$models.openTimes.user"
      }},
      {"$project":{"models":0}}
    ])
    

    【讨论】:

    猜你喜欢
    • 2019-04-18
    • 2017-03-24
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-06
    • 1970-01-01
    • 2020-07-28
    相关资源
    最近更新 更多