根据 mongodb 中另一个数组字段的值将数组字段添加到集合
Adding an array field to a collection based on values of another array field in mongodb
我有一个集合,它具有以下结构,如一个文档所示
{
_id : 1,
array1 : [{fld1 : 'doc1e1fld1', fld2: 'doc1e1fld2'},{fld1:'doc1e2fld1',fld2: 'doc1e2fld2'}]
}
我想向集合中的所有元素添加另一个字段并设置值,使上面修改后的文档看起来像:
{
_id : 1,
array1 : [{fld1 : 'doc1e1fld1', fld2: 'doc1e1fld2'},{fld1:'doc1e2fld1',fld2: 'doc1e2fld2'}],
array2 : ['doc1e1fld1','doc1e2fld1']
}
基本上是向集合中的所有文档添加一个新的数组元素,并将其内容设置为一个数组,该数组是文档 array1 中所有元素的 fld1 值。
我看过 Update MongoDB field using value of another field 但不知何故我不明白如何提取某些元素。
因此,您应该已经从您引用的问题中意识到,在更新另一个字段时,您实际上不能在不实际查找文档并循环结果以生成更新的情况下引用文档中的另一个值。
所以最重要的是,您真的可以在代码中执行此操作,读取每个文档并提取新值以形成新数组。可以在更新中使用 $set
or possibly more safely by using $push
and $each
运算符创建新数组。
理想情况下,您也可以使用 Bulk Operations API 来获得最佳的更新形式。
最后你也可以将一些数组构造工作量委托给 aggregation framework 而不是在客户端代码中处理所有这些,但是仍然需要对结果执行更新:
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
运算符一起使用,以便从数组中提取所需的元素,或者考虑到您并不是真正的 "aggregating",您也可以使用类似的方法在代码中执行此操作无论如何。这里的主要情况是您需要在代码中循环结果,无论您使用何种语言。
当然,如果您可以只使用更改后的结果创建一个 "new" 集合,那么聚合的 $out
管道阶段可能很适合您:
db.collection.aggregate([
{ "$project": {
"array1": 1,
"array2": {
"$map": {
"input": "array1",
"as": "el",
"in": "$$el.fld1"
}
}
}},
{ "$out": "newcollection" }
]);
简而言之,尽管您需要部分或全部这些技术以获得您正在寻找的改变后的收集结果。所以要么直接使用它,要么实现其中的一些。
我有一个集合,它具有以下结构,如一个文档所示
{
_id : 1,
array1 : [{fld1 : 'doc1e1fld1', fld2: 'doc1e1fld2'},{fld1:'doc1e2fld1',fld2: 'doc1e2fld2'}]
}
我想向集合中的所有元素添加另一个字段并设置值,使上面修改后的文档看起来像:
{
_id : 1,
array1 : [{fld1 : 'doc1e1fld1', fld2: 'doc1e1fld2'},{fld1:'doc1e2fld1',fld2: 'doc1e2fld2'}],
array2 : ['doc1e1fld1','doc1e2fld1']
}
基本上是向集合中的所有文档添加一个新的数组元素,并将其内容设置为一个数组,该数组是文档 array1 中所有元素的 fld1 值。
我看过 Update MongoDB field using value of another field 但不知何故我不明白如何提取某些元素。
因此,您应该已经从您引用的问题中意识到,在更新另一个字段时,您实际上不能在不实际查找文档并循环结果以生成更新的情况下引用文档中的另一个值。
所以最重要的是,您真的可以在代码中执行此操作,读取每个文档并提取新值以形成新数组。可以在更新中使用 $set
or possibly more safely by using $push
and $each
运算符创建新数组。
理想情况下,您也可以使用 Bulk Operations API 来获得最佳的更新形式。
最后你也可以将一些数组构造工作量委托给 aggregation framework 而不是在客户端代码中处理所有这些,但是仍然需要对结果执行更新:
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
运算符一起使用,以便从数组中提取所需的元素,或者考虑到您并不是真正的 "aggregating",您也可以使用类似的方法在代码中执行此操作无论如何。这里的主要情况是您需要在代码中循环结果,无论您使用何种语言。
当然,如果您可以只使用更改后的结果创建一个 "new" 集合,那么聚合的 $out
管道阶段可能很适合您:
db.collection.aggregate([
{ "$project": {
"array1": 1,
"array2": {
"$map": {
"input": "array1",
"as": "el",
"in": "$$el.fld1"
}
}
}},
{ "$out": "newcollection" }
]);
简而言之,尽管您需要部分或全部这些技术以获得您正在寻找的改变后的收集结果。所以要么直接使用它,要么实现其中的一些。