在Array中对嵌入式文档进行排序并获取详细信息

时间:2016-03-03 21:29:40

标签: node.js mongodb mongoose aggregation-framework

我有一个像这样的猫鼬模型:

var activityItem = mongoose.Schema({
    timestampValue: Number,
    xabc: String,
    full: Boolean,
    comp: Boolean
});

var ABC = mongoose.Schema({
    activity: [activityItem],
    user: {
        type: mongoose.Schema.ObjectId,
        ref: 'User'
    },
    username: String
});

我想获得timestampValue小于特定值的activityItem数组元素。另外,我想先根据activity

timestampValue数组进行排序

这是我目前拥有的代码。它没有用。

UserActivity.findOne({
    'user': current_user,
    'activity' : {
        $all: [
            {
                "$elemMatch": {
                    timestampValue: {
                        $lte: time
                    }
                }
            }
        ]
    }
},

function(err, user){

})

示例文档结构:

{
    "_id" : ObjectId("56d5e88adfd14baf1848a7c6"),
    "user" : ObjectId("56bf225342e662f4277ded73"),
    "notifications" : [],
    "completed" : [],
    "activity" : [ 
        {
            "timestampValue": 1456902600000,
            "xabc": "Some value",
            "full": true,
            "comp": false,
            "_id" : ObjectId("56d5e88adfd14baf1848a7d2")
        }, 
        {
            "timestampValue": 1456702600000,
            "xabc": "Some other value",
            "full": true,
            "comp": false,
            "_id" : ObjectId("56d5e88adfd14baf1848a7d3")
        }
    ],
    "__v" : 1
}

POST调用具有以下参数

hash: "2e74aaaf42aa5ea733be963cb61fc5ff"
time: 1457202600000
一旦我拥有来自mongo的文档,

hash就会出现 time是一个unix时间戳值。

它不是只返回小于time值的元素,而是返回所有数组元素。在查询之前,我尝试使用聚合框架对数组进行排序,但是无法解决它。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

请尝试通过以下aggregation进行操作

ABS.aggregate([
    // filter the document by current_user
    {$match: {user: ObjectId(current_user)}},
    // unwind the activity array
    {$unwind: '$activity'},
    // filter the timestampValue less than time
    {$match: {'activity.timestampValue': {$lte: time}}},
    // sort activity by timestampValue in ascending order
    {$sort: {'activity.timestampValue': 1}},
    // group by _id, and assemble the activity array.
    {$group: {_id: '$_id', user: {$first: '$user'},activity: {$push: '$activity'}}}
], function(err, results){
    if (err)
        throw err;

    // populate user to get details of user information if needed
    //ABS.populate( results, { "path": "user" }, function(err, rets) {
        //
    //});
});

答案 1 :(得分:0)

嗯,除非你有MongoDB 3.2,否则MongoDb聚合管道看起来有点棘手,但你绝对可以 借助map-reduce实现你的结果。

e.g。

  

MongoDB版本< 3.2

var findActivities = function (time) {
    db.col.mapReduce(function () {
        var item = Object.assign({}, this);
        delete item.activity;
        item.activity = [];

        for (var i = 0; i < this.activity.length; i++) {
            if (this.activity[i].timestampValue <= time) {
                item.activity.push(this.activity[i]);
            }
        }

        emit(item._id, item);
    }, function (k, v) {
        return {items: v};
    }, {
        out: {"inline": true},
        scope: {time: time}
    }).results.forEach(function (o) {
        printjson(o); // Or perform action as appropriate 
    });
};

在调用findActivities(1456802600000)时根据您的示例数据,它将只查找并返回符合条件的文档。

{ 
    "_id" : ObjectId("56d5e88adfd14baf1848a7c6"), 
    "value" : {
        "_id" : ObjectId("56d5e88adfd14baf1848a7c6"), 
        "user" : ObjectId("56bf225342e662f4277ded73"), 
        "notifications" : [

        ], 
        "completed" : [

        ], 
        "__v" : NumberInt(1), 
        "activity" : [
            {
                "timestampValue" : NumberLong(1456702600000), 
                "xabc" : "Some other value", 
                "full" : true, 
                "comp" : false, 
                "_id" : ObjectId("56d5e88adfd14baf1848a7d3")
            }
        ]
    }
}
  

MongoDB版本3.2 +

db.col.aggregate([
    {$project:{user:1, notifications:1, completed:1, activity:{
      $filter:{input: "$activity", as: "activity", cond:{
        $lte: ["$$activity.timestampValue", 1456802600000]}}}}}
])

两种解决方案都具有相同的输出。