Mongodb: 子文档数组的聚合值
Mongodb: aggregate values on array of subdocuments
我有文档集:
{
"_id": ObjectId("55dc62647cda24224372e308"),
"last_modified": ISODate("2015-07-01T15:57:26.874Z"),
"services": [
{"last_modified": ISODate("2015-05-08T07:10:11.250Z")},
{...}
]
}
并且我需要通过查找其服务的最大 last_updated 值来刷新文档的 last_modified 字段:
>db.documents.find().map(function(d){
db.documents.update(
{_id: d._id},
{$set: {last_updated: Math.max(d.services.last_updated)}}
)
})
Tue Aug 25 16:01:20.536 TypeError: Cannot read property 'last_modified' of undefined
如何访问和聚合数组中的 属性 个子文档?
这里的基本过程是,你需要从数组中获取最大排序日期,并从那里获取值。当然你需要一个循环,你不能直接在更新语句中访问文档的值。所以你需要先阅读它,但是 Bulk 操作在这里有帮助:
var bulk = db.documents.initializeOrderedBulkOp(),
count = 0;
db.documents.find().forEach(function(doc) {
var last_modified = doc.services.sort(function(a,b) {
return a.last_modified < b.last_modified;
}).slice(-1)[0].last_modified;
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "last_modified": last_modified }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.documents.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
更好的是,考虑在添加新项时对数组本身进行排序。这基本上是通过 $sort
modifier to $push
完成的
db.documents.update(
{ "_id": id },
{ "$push": {
"services": {
"$each": [{ "last_modified": date }],
"$sort": { "last_modified": 1 }
}}
)
或者甚至忘记 $sort
因为所有数组值无论如何都会附加到末尾,除非您告诉操作否则。
那你基本上可以用$slice
.
来缩短程序
var bulk = db.documents.initializeOrderedBulkOp(),
count = 0;
db.documents.find(
{},
{
"last_modified": { "$slice": -1}
}
).forEach(function(doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "last_modified": doc.last_modified[0] }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.documents.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
聚合框架可以在这里使用,但考虑到从每个文档的对象中获取最大日期值是多么简单,实际上没有必要。
var bulk = db.documents.initializeOrderedBulkOp(),
count = 0;
db.documents.aggregate([
{ "$unwind": "$services" },
{ "$group": {
"_id": "$_id",
"last_modified": { "$max": "$services.last_modified" }
}}
]).forEach(function(doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "last_modified": doc.last_modified }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.documents.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
并且由于 $unwind
的使用,这实际上比必要的成本高得多。
我有文档集:
{
"_id": ObjectId("55dc62647cda24224372e308"),
"last_modified": ISODate("2015-07-01T15:57:26.874Z"),
"services": [
{"last_modified": ISODate("2015-05-08T07:10:11.250Z")},
{...}
]
}
并且我需要通过查找其服务的最大 last_updated 值来刷新文档的 last_modified 字段:
>db.documents.find().map(function(d){
db.documents.update(
{_id: d._id},
{$set: {last_updated: Math.max(d.services.last_updated)}}
)
})
Tue Aug 25 16:01:20.536 TypeError: Cannot read property 'last_modified' of undefined
如何访问和聚合数组中的 属性 个子文档?
这里的基本过程是,你需要从数组中获取最大排序日期,并从那里获取值。当然你需要一个循环,你不能直接在更新语句中访问文档的值。所以你需要先阅读它,但是 Bulk 操作在这里有帮助:
var bulk = db.documents.initializeOrderedBulkOp(),
count = 0;
db.documents.find().forEach(function(doc) {
var last_modified = doc.services.sort(function(a,b) {
return a.last_modified < b.last_modified;
}).slice(-1)[0].last_modified;
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "last_modified": last_modified }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.documents.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
更好的是,考虑在添加新项时对数组本身进行排序。这基本上是通过 $sort
modifier to $push
db.documents.update(
{ "_id": id },
{ "$push": {
"services": {
"$each": [{ "last_modified": date }],
"$sort": { "last_modified": 1 }
}}
)
或者甚至忘记 $sort
因为所有数组值无论如何都会附加到末尾,除非您告诉操作否则。
那你基本上可以用$slice
.
var bulk = db.documents.initializeOrderedBulkOp(),
count = 0;
db.documents.find(
{},
{
"last_modified": { "$slice": -1}
}
).forEach(function(doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "last_modified": doc.last_modified[0] }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.documents.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
聚合框架可以在这里使用,但考虑到从每个文档的对象中获取最大日期值是多么简单,实际上没有必要。
var bulk = db.documents.initializeOrderedBulkOp(),
count = 0;
db.documents.aggregate([
{ "$unwind": "$services" },
{ "$group": {
"_id": "$_id",
"last_modified": { "$max": "$services.last_modified" }
}}
]).forEach(function(doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "last_modified": doc.last_modified }
});
count++;
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.documents.initializeOrderedBulkOp();
}
});
if ( count % 1000 != 0 )
bulk.execute();
并且由于 $unwind
的使用,这实际上比必要的成本高得多。