MongoDB - 将简单字段更改为对象
MongoDB - change simple field into an object
在 MongoDB 中,我想更改我的文档结构:
{
discount: 10,
discountType: "AMOUNT"
}
至:
{
discount: {
value: 10,
type: "AMOUNT"
}
}
所以我在 mongo shell 中尝试了以下查询:
db.discounts.update({},
{
$rename: {
discount: "discount.value",
discountType: "discount.type"
}
},
{multi: true}
)
但它抛出一个错误:
"writeError" : {
"code" : 2,
"errmsg" : "The source and target field for $rename must not be on the same path: discount: \"discount.value\""
}
我想到的解决方法是分两步完成:首先将新结构分配给新字段(比如 discount2
),然后将其重命名为 discount
。但也许有一种方法可以一步到位?
您收到此错误的原因是 documentation 中提到的:
The $rename
operator logically performs an $unset
of both the old name and the new name, and then performs a $set
operation with the new name. As such, the operation may not preserve the order of the fields in the document; i.e. the renamed field may move within the document.
问题在于您不能在 MongoDB
中同时 $set
and $unset
同一字段。
解决方案是使用批量操作来更新文档以更改其结构,即使在这种情况下,您也需要使用集合中不存在的字段名称。当然,完成这一切的最佳方法是使用 "Bulk" 操作以获得最高效率
MongoDB 3.2 或更高版本
MongoDB 3.2 弃用 Bulk() and its associated methods. You need to use the .bulkWrite()
方法。
var operations = [];
db.discounts.find().forEach(function(doc) {
var discount = doc.discount;
var discountType = doc.discountType;
var operation = { 'updateOne': {
'filter': { '_id': doc._id },
'update': {
'$unset': { 'discount': '', 'discountType': '' },
'$set': { 'discounts.value': discount, 'discounts.type': discountType }
}
}};
operations.push(operation);
});
operations.push( {
ordered: true,
writeConcern: { w: "majority", wtimeout: 5000 }
});
db.discounts.bulkWrite(operations);
产生:
{
"_id" : ObjectId("56682a02e6a2321d88f6d078"),
"discounts" : {
"value" : 10,
"type" : "AMOUNT"
}
}
MongoDB 2.6
在 MongoDB 3.2 之前并使用 MongoDB 2.6 或更高版本,您可以使用“批量”API.
var bulk = db.discounts.initializeOrderedBulkOp();
var count = 0;
db.discounts.find().forEach(function(doc) {
var discount = doc.discount;
var discountType = doc.discountType;
bulk.find( { '_id': doc._id } ).updateOne( {
'$unset': { 'discount': '', 'discountType': '' },
'$set': { 'discounts.value': discount, 'discounts.type': discountType } });
count++;
if (count % 500 === 0) {
bulk.execute();
bulk = db.discounts.initializeOrderedBulkOp();
}
})
if (count > 0)
bulk.execute();
此查询产生与上一个相同的结果。
感谢 Update MongoDB field using value of another field 的回答,我找到了以下解决方案:
db.discounts.find().snapshot().forEach(
function(elem) {
elem.discount = {
value: elem.discount,
type: elem.discountType
}
delete elem.discountType;
db.discounts.save(elem);
}
)
我非常喜欢,因为源代码读起来很好,但是对于大量文档来说性能很差。
最简单的方法是按照您在问题中提到的那样分两步完成;最初将 discount
重命名为临时字段名称,以便在第二步中重复使用:
db.discounts.update({}, {$rename: {discount: 'temp'}}, {multi: true})
db.discounts.update({},
{$rename: {temp: 'discount.value', discountType: 'discount.type'}},
{multi: true})
在 MongoDB 中,我想更改我的文档结构:
{
discount: 10,
discountType: "AMOUNT"
}
至:
{
discount: {
value: 10,
type: "AMOUNT"
}
}
所以我在 mongo shell 中尝试了以下查询:
db.discounts.update({},
{
$rename: {
discount: "discount.value",
discountType: "discount.type"
}
},
{multi: true}
)
但它抛出一个错误:
"writeError" : {
"code" : 2,
"errmsg" : "The source and target field for $rename must not be on the same path: discount: \"discount.value\""
}
我想到的解决方法是分两步完成:首先将新结构分配给新字段(比如 discount2
),然后将其重命名为 discount
。但也许有一种方法可以一步到位?
您收到此错误的原因是 documentation 中提到的:
The
$rename
operator logically performs an$unset
of both the old name and the new name, and then performs a$set
operation with the new name. As such, the operation may not preserve the order of the fields in the document; i.e. the renamed field may move within the document.
问题在于您不能在 MongoDB
中同时 $set
and $unset
同一字段。
解决方案是使用批量操作来更新文档以更改其结构,即使在这种情况下,您也需要使用集合中不存在的字段名称。当然,完成这一切的最佳方法是使用 "Bulk" 操作以获得最高效率
MongoDB 3.2 或更高版本
MongoDB 3.2 弃用 Bulk() and its associated methods. You need to use the .bulkWrite()
方法。
var operations = [];
db.discounts.find().forEach(function(doc) {
var discount = doc.discount;
var discountType = doc.discountType;
var operation = { 'updateOne': {
'filter': { '_id': doc._id },
'update': {
'$unset': { 'discount': '', 'discountType': '' },
'$set': { 'discounts.value': discount, 'discounts.type': discountType }
}
}};
operations.push(operation);
});
operations.push( {
ordered: true,
writeConcern: { w: "majority", wtimeout: 5000 }
});
db.discounts.bulkWrite(operations);
产生:
{
"_id" : ObjectId("56682a02e6a2321d88f6d078"),
"discounts" : {
"value" : 10,
"type" : "AMOUNT"
}
}
MongoDB 2.6
在 MongoDB 3.2 之前并使用 MongoDB 2.6 或更高版本,您可以使用“批量”API.
var bulk = db.discounts.initializeOrderedBulkOp();
var count = 0;
db.discounts.find().forEach(function(doc) {
var discount = doc.discount;
var discountType = doc.discountType;
bulk.find( { '_id': doc._id } ).updateOne( {
'$unset': { 'discount': '', 'discountType': '' },
'$set': { 'discounts.value': discount, 'discounts.type': discountType } });
count++;
if (count % 500 === 0) {
bulk.execute();
bulk = db.discounts.initializeOrderedBulkOp();
}
})
if (count > 0)
bulk.execute();
此查询产生与上一个相同的结果。
感谢 Update MongoDB field using value of another field 的回答,我找到了以下解决方案:
db.discounts.find().snapshot().forEach(
function(elem) {
elem.discount = {
value: elem.discount,
type: elem.discountType
}
delete elem.discountType;
db.discounts.save(elem);
}
)
我非常喜欢,因为源代码读起来很好,但是对于大量文档来说性能很差。
最简单的方法是按照您在问题中提到的那样分两步完成;最初将 discount
重命名为临时字段名称,以便在第二步中重复使用:
db.discounts.update({}, {$rename: {discount: 'temp'}}, {multi: true})
db.discounts.update({},
{$rename: {temp: 'discount.value', discountType: 'discount.type'}},
{multi: true})