Reputation: 17586
I am working with Mongoose, I have a collection that has documents like this
{
"_id" : 1,
"body" : "[{\"order_id\":\"647936\",\"order_datetime\":\"2015-12-02 11:10:00\"}]",
"user_info" : {
"contact_email" : "[email protected]",
"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" : "[email protected]",
"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" : "[email protected]",
"contact_phone" : "1234567",
},
"type" : "ORDERS",
"version" : 3
}
As you can see in body field you can see the order_id , so same order_id can be repeated in multiple in documents but the version will be different.
What I want is I want to search for the maximum version number for a given order_id .
In my case it would be 3 .
I tried to use simple queries like
myCollection.aggregate([
{ "$match" : { "body.order_id" : 647936 } },
{ "$group": {
"_id" :"version",
"max": { "$max": "version" }
}}
] , function(err, data){
console.log(err);
console.log(data);
});
But the result is
null
[]
** Note that my mongoose connection is working fine and I can do some simple queries and results are OK.
Upvotes: 0
Views: 292
Reputation: 50416
Your data is the problem here since what seems to be intended as a structured document has been stored as a string:
// Bad bit
"body" : "[{\"order_id\":\"647936\",\"order_datetime\":\"2015-12-02 11:10:00\"}]",
Instead you would want this:
// Acutally data and not a string
"body" : [{ "order_id": "647936", "order_datetime": ISODate("2015-12-02 11:10:00.000Z" }],
With data like that, getting the latest version is a simple matter of ordering the results, without the overhead of .aggregate()
:
myCollection.find({ "body.order_id": "647936" })
.sort({ "version": -1 }).limit(1).exec(function(err,result) {
})
No need to aggregate and it's much faster than doing so, as you are just picking out the document with the latest (largest) version number.
In order to "fix" the data you can do something like this as a "one shot" execution in the 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();
You might also want to convert those "strings" other than the date to numeric values in a similar fashion and change appropriately in the query.
Upvotes: 1