用文档中另一个字段的值更新字段[重复]
Posted
技术标签:
【中文标题】用文档中另一个字段的值更新字段[重复]【英文标题】:Update field with another field's value in the document [duplicate] 【发布时间】:2011-02-06 02:12:39 【问题描述】:我有一个集合 t1
,其架构中有以下字段
_id, field1, field1
我想设置field2
的值field1
,比如sql:
update t1 set field1=field2;
我如何在 MongoDB 中做到这一点?
【问题讨论】:
非常相似的问题:***.com/questions/3974985/… 【参考方案1】:这里有好消息和坏消息。
坏消息是 AFAIK 你不能用一个 update() 调用来做到这一点 - mongo 不支持在更新中引用当前对象。
好消息是还有其他方法可以做到这一点,例如你可以运行一个 forEach 循环:
db.item.find(conditions...).snapshot().forEach( function (doc)
doc.field1 = doc.field2;
db.item.save(doc);
);
您可以在管理 shell('mongo' 命令)中运行 forEach,或者通过特定驱动程序的某些方法(例如,在 php 中,我希望它可以与 mongodb.execute() 一起使用,如下所述: http://www.php.net/manual/en/mongodb.execute.php)
【讨论】:
因为在 forEach 循环中调用了 save(),所以光标会被弄乱,函数可能会被每个文档多次调用。解决方法是在foreach之前调用snapshot():db.item.find(blah).snapshot().forEach() 谢谢。我不知道要按预期工作的 snapshot() 要求。 TBH 一开始我很吃惊,一个名为“forEach”的函数并不能保证它的名字所暗示的含义(因为它类似于你在编程语言的集合库中可以找到的),但话又说回来,我知道可能有有很多理由这样做。 没有原子方法可以做到这一点吗?这个解决方案似乎不是很健壮。 对 mongodb 3.0 仍然如此吗? @tacone 是的。如果您具有在停机时间运行的优势,那么两种解决方案都会为您提供相似的结果,但删除并重命名可能更容易知道您“完成”了。如果您有一个热同步,那么就地执行它可能是一个更简单的解决方案,因为您可能能够修复数据源,然后循环直到它运行干净。可能是。我之前没有在生产中进行过热同步 :) 只是想指出同步问题,真的。【参考方案2】:从 3.4 版本开始,我们可以使用$addFields
聚合管道操作符,无需客户端处理,这是最有效的方式。
db.collection.aggregate(
[
"$addFields": "field2": "$field1" ,
"$out": "collection"
]
)
在 3.4 版之前,我们需要迭代 Cursor
对象并使用 $set
运算符添加具有现有“field1”值的新字段。您需要使用“批量”操作来执行此操作以获得最大效率。
MongoDB 3.2 弃用了 Bulk()
及其 associated methods,,因此从 3.2 开始,您需要使用 bulkWrite
方法。
var requests = [];
db.collection.find(, 'field1': 1 ).snapshot().forEach(document =>
requests.push(
'updateOne':
'filter': '_id': document._id ,
'update': '$set': 'field2': document.field1
);
if (requests.length === 1000)
//Execute per 1000 operations and re-init
db.collection.bulkWrite(requests);
requests = [];
);
if(requests.length > 0)
db.collection.bulkWrite(requests);
从版本 2.6 到 3.0,您可以使用 Bulk
API。
var bulk = db.collection.initializeUnorderedBulOp();
var count = 0;
db.collection.find(, 'field1': 1 ).snapshot().forEach(function(document)
bulk.find( '_id': document._id ).updateOne(
'$set': 'field2': document.field1
);
count++;
if(count%1000 === 0)
// Excecute per 1000 operations and re-init
bulk.execute();
bulk = db.collection.initializeUnorderedBulkOp();
)
// clean up queues
if(count > 0)
bulk.execute();
【讨论】:
在我的测试中,我发现聚合方法要快得多。我的样本数据有 150K 文档,需要 5 秒才能重塑,而 .foreach 方法需要约 1.5 分钟。采用聚合方法时需要考虑哪些注意事项/陷阱?aggregate
和 out
不合适,如果需要 match
:最终集合将仅包含匹配的文档。【参考方案3】:
这可以通过:
db.nameOfCollection.find().forEach(
function (elem)
db.nameOfCollection.update(
_id: elem._id
,
$set:
field2: elem.field1
);
);
【讨论】:
您复制粘贴 ***.com/a/14423151/2054072 失败 是的,@Deejay 如果您在 *** 的其他地方找到答案,请参考链接,这将有助于我们与老师本人/她自己进行交叉提问。以上是关于用文档中另一个字段的值更新字段[重复]的主要内容,如果未能解决你的问题,请参考以下文章