MongoDB返回带有条件的数组

时间:2014-06-12 12:48:55

标签: node.js mongodb

我需要执行mongoDB查询以获取日期之间的用户状态。

这是一个文档示例:

{
    "_id" : ObjectId("538efd918163b19307c59e8e"),
    "username" : "admin",
    "hashedPassword" : "9qm4ufCPOCeU4AoBIMCJyf8oIvs8vWUYKIbImhc1N9HJrRKzCwCbeGNBsuOWnQ2kMbM635KmingRkn31wvHPQ/1bvs8Msg2rUchybaVvFmpy15A9Pnhb1BDHSLPftn0v8mSyhZQuOpP7Goirg07CGDPvJQqhN6oH6g0+iBTliAs=",
    "salt" : "EHLY4edLmrq7Nj4zRqh7Loow/O34pHNiWQ1i4vo8+SJTl82phMokAyTSr4MNKBeMMhJgCof1uK+3++PlXp5Y3I0SL3XkzJsSWG9K5oXJCE7B3j0Kazj4IlAllOEcXwMeuBVTnTgnBi9pUqdWyDysHG893oMVmr3VizycL/Iz484=",
    "realName" : "Administrator",
    "roles" : [ 
        "admin", 
        "operator", 
        "technician"
    ],
    "status" : [],
    "states" : [ 
        {
            "status" : "vacances",
            "date" : ISODate("2014-06-09T11:42:02.756Z")
        }, 
        {
            "status" : "busy",
            "date" : ISODate("2014-06-09T11:42:03.443Z")
        }, 
        {
            "status" : "eating",
            "date" : ISODate("2012-06-09T11:42:04.080Z")
        }, 
        {
            "status" : "busy",
            "date" : ISODate("2014-06-09T11:49:53.765Z")
        }, 
        {
            "status" : "vacances",
            "date" : ISODate("2014-06-09T11:49:54.402Z")
        }, 
        {
            "status" : "eating",
            "date" : ISODate("2014-06-09T11:49:56.409Z")
        }, 
        {
            "status" : "resting",
            "date" : ISODate("2014-06-09T11:49:57.114Z")
        }, 
        {
            "status" : "eating",
            "date" : ISODate("2014-06-09T12:24:38.880Z")
        }, 
        {
            "status" : "busy",
            "date" : ISODate("2014-06-09T14:51:13.440Z")
        }, 
        {
            "status" : "free",
            "date" : ISODate("2014-06-09T14:51:20.940Z")
        }, 
        {
            "status" : "vacances",
            "date" : ISODate("2014-06-12T11:05:36.448Z")
        }, 
        {
            "status" : "busy",
            "date" : ISODate("2014-06-12T11:05:37.425Z")
        }
    ]
}

然后,想要获取日期之间的状态,我有这个查询:

var collection = db.collection('users');
    collection.aggregate([
        {$match: {$and: [
            { _id: new ObjectID(id)},
            { 'states.date': { $gt: new Date(from), $lte: new Date(to) }}
        ]}},
        {$unwind: "$states"},
        {$sort: {"states.date": -1}},
        {$group: {_id: "$_id", states: {$push: "$states"}}}
    ], function (e, doc) {
        if (e) {
            error(e);
        }
        success(doc);
    });

结果是错误的,因为返回我用户的所有状态,不仅仅是在日期查询之间..如何减少mongodb查询中的响应?

2 个答案:

答案 0 :(得分:1)

您应该在$unwind阵列后过滤文档。您的第一个匹配项将匹配整个文档,但不会过滤掉数组中的文档:

var collection = db.collection('users');
    collection.aggregate([
        {$match: { _id: new ObjectID(id) } }, 
        {$unwind: "$states"},
        {$match: { 'states.date': { $gt: new Date(from), $lte: new Date(to) }}},
        {$sort: {"states.date": -1}},
        {$group: {_id: "$_id", states: {$push: "$states"}}}
    ], function (e, doc) {
        if (e) {
            error(e);
        }
        success(doc);
    });

修改

如果您正在寻找特定用户,也无需在第一个$match中搜索日期范围。仅按_id进行过滤将在该字段上使用默认索引,并且速度会快得多。

答案 1 :(得分:0)

您的第一个$match条件仅匹配文档而不匹配数组成员。到"过滤"你需要在$match之后实际$unwind

    collection.aggregate([
        {$match: {$and: [
            { _id: new ObjectID(id)},
            { 'states.date': { $gt: new Date(from), $lte: new Date(to) }}
        ]}},
        {$unwind: "$states"},
        {$match: {$and: [
            { 'states.date': { $gt: new Date(from), $lte: new Date(to) }}
        ]}},
        {$sort: {"states.date": -1}},
        {$group: {_id: "$_id", states: {$push: "$states"}}}
    ], function (e, doc) {
        if (e) {
            error(e);
        }
        success(doc);
    });