我有一个集合,它具有以下结构,由一个文档表示
{
_id : 1,
array1 : [{fld1 : 'doc1e1fld1', fld2: 'doc1e1fld2'},{fld1:'doc1e2fld1',fld2: 'doc1e2fld2'}]
}
我想向集合中的ALL元素添加另一个字段,并设置值,使上面修改的文档看起来像:
{
_id : 1,
array1 : [{fld1 : 'doc1e1fld1', fld2: 'doc1e1fld2'},{fld1:'doc1e2fld1',fld2: 'doc1e2fld2'}],
array2 : ['doc1e1fld1','doc1e2fld1']
}
基本上是向集合中的所有文档添加一个新的数组元素,并将其内容设置为一个数组,该数组是文档array1中所有元素的fld1值。
我看了使用另一个字段的值更新MongoDB字段,但不知何故,我不明白如何提取某些元素。
因此,您应该已经从您引用的问题中意识到,在更新另一个字段时,您实际上无法引用文档中的另一个值,而无需实际查找文档并循环结果以生成更新。
所以底线是你真的会在代码中这样做,阅读每个文档并从中提取新值来形成你的新数组。创建这个新数组可以使用$set
或者通过在更新中使用$push
和$each
运算符来更安全。
理想情况下,您还可以使用批量操作API来获得最佳的更新形式。
最后,您还可以将一些数组构造工作负载委托给聚合框架,而不是在客户端代码中处理所有工作负载,但仍然需要对结果执行更新:
var bulk = db.collection.initializeOrderedBulkOp();
var count = 0;
var cursor = db.collection.aggregate([
{ "$project": {
"array2": {
"$map": {
"input": "array1",
"as": "el",
"in": "$$el.fld1"
}
}
}}
]);
cursor.forEach(function(doc) {
bulk.find({ "_id": doc._id }).updateOne({
"$push": { "array2": { "$each": doc.array2 } }
});
count++;
// send and drain once every 1000 documents
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.collection.initializeOrderedBulkOp();
}
});
// If the counter is uneven then send
if ( count % 1000 != 0 )
bulk.execute();
就是这样。您可以像这样使用带有$map
运算符的聚合框架,以便从数组中提取所需的元素,或者您可以使用类似的方法在代码中执行此操作,因为您实际上并没有“聚合”任何东西。这里的主要情况是,您将需要在代码中循环结果,无论您使用哪种语言。
当然,如果您可以只使用更改的结果创建一个“新”集合,那么聚合的$out
管道阶段可能非常适合您:
db.collection.aggregate([
{ "$project": {
"array1": 1,
"array2": {
"$map": {
"input": "array1",
"as": "el",
"in": "$$el.fld1"
}
}
}},
{ "$out": "newcollection" }
]);
简而言之,尽管您需要一些或所有这些技术来获得您正在寻找的更改的集合结果。所以要么直接使用它,要么实现其中的一些。