如何在这种情况下使用where情况获得最大值Mongoose / Node

时间:2016-01-28 02:32:37

标签: node.js mongodb mongoose mongodb-query

我正在使用Mongoose,我有一个包含这样的文档的集合

{
"_id" : 1,
    "body" : "[{\"order_id\":\"647936\",\"order_datetime\":\"2015-12-02 11:10:00\"}]",
    "user_info" : {
        "contact_email" : "test@test.com",
        "contact_phone" : "1234567",
    },
    "type" : "ORDERS",
    "version" : 1
}

{
"_id" : 2,
    "body" : "[{\"order_id\":\"647936\",\"order_datetime\":\"2015-12-02 11:10:00\"}]",
    "user_info" : {
        "contact_email" : "test@test.com",
        "contact_phone" : "1234567",
    },
    "type" : "ORDERS",
    "version" : 2
}

{
"_id" : 3,
    "body" : "[{\"order_id\":\"647936\",\"order_datetime\":\"2015-12-02 11:10:00\"}]",
    "user_info" : {
        "contact_email" : "test@test.com",
        "contact_phone" : "1234567",
    },
    "type" : "ORDERS",
    "version" : 3
}

正如您在body字段中看到的那样,您可以看到order_id,因此相同的order_id可以在多个文档中重复,但版本会有所不同。

  

我想要的是我想搜索a的最大版本号   给定order_id。

     

就我而言,它将是3。

我尝试使用像

这样的简单查询
myCollection.aggregate([
                        { "$match" : { "body.order_id" : 647936 } },
                        { "$group": {
                            "_id" :"version",
                            "max": { "$max": "version" }
                            }}
                        ] , function(err, data){

                                console.log(err);
                                console.log(data);
                            });

但结果是

null
[]

**请注意我的mongoose连接工作正常,我可以做一些简单的查询,结果还可以。

1 个答案:

答案 0 :(得分:1)

您的数据是此处的问题,因为看起来像结构化文档的内容已存储为字符串:

// Bad bit
"body" : "[{\"order_id\":\"647936\",\"order_datetime\":\"2015-12-02 11:10:00\"}]",

相反,你会想要这个:

// Acutally data and not a string
"body" : [{ "order_id": "647936", "order_datetime": ISODate("2015-12-02 11:10:00.000Z" }],

使用这样的数据,获取最新版本只是对结果进行排序的简单问题,而没有.aggregate()的开销:

myCollection.find({ "body.order_id": "647936" })
    .sort({ "version": -1 }).limit(1).exec(function(err,result) {

})

无需聚合,而且速度要快得多,因为您只需选择具有最新(最大)版本号的文档。

为了“修复”数据,您可以在shell中执行类似“一次性”执行的操作:

var bulk = db.myCollection.initializeOrderedBulkOp(),
    count = 0;

// query selects just those "body" elements that are currently a string
db.myCollection.find({ "body": { "$type": 2 } }).forEach(function(doc) {
    var fixBody = JSON.parse(doc.body);  // Just parse the string
    fixBody.forEach(function(el) {
        // Fix dates
        el.order_datetime = new Date(
            Date.parse(el.order_datetime.split(" ").join("T") + "Z")
        );
    });

    // And queue an update to overwrite the "body" data
    bulk.find({ "_id": doc._id }).updateOne({ 
        "$set": { "body": fixBody }
    });
    count++;

    // Send every 1000
    if ( count % 1000 == 0 ) {
        bulk.execute();
        bulk = db.myCollection.initializeOrderedBulkOp(),
    }
});

// Send any remaining batched
if ( count % 1000 != 0 )
    bulk.execute();

您可能还希望以类似的方式将日期以外的“字符串”转换为数值,并在查询中进行适当更改。