MongoDB - 将简单字段更改为对象

时间:2015-12-09 11:55:34

标签: mongodb mongodb-query mongo-shell

在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 。但也许有一种方法可以一步到位吗?

3 个答案:

答案 0 :(得分:2)

最简单的方法是在你提出的问题中分两步完成;最初将{'_Application__author': 'me', '_Application__name': 'my first app'} Traceback (most recent call last): File "/Users/reno/Desktop/testtt.py", line 42, in <module> request = my_app + '.' + attribute TypeError: unsupported operand type(s) for +: 'Application' and 'str' [Finished in 0.1s with exit code 1] [shell_cmd: python -u "/Users/reno/Desktop/testtt.py"] [dir: /Users/reno/Desktop] [path: /usr/bin:/bin:/usr/sbin:/sbin] 重命名为临时字段名称,以便在第二步中重复使用它:

discount

答案 1 :(得分:1)

您收到此错误的原因是因为documentation

中提到的
  

$rename运算符逻辑上执行旧名称和新名称的$unset,然后使用新名称执行$set操作。因此,操作可能不保留文档中字段的顺序;即重命名的字段可以在文档中移动。

问题在于MongoDB中您不能同时$set$unset同一个字段。

解决方案是使用批量操作来更新文档以更改其结构,即使在这种情况下,您也需要使用集合中不存在的字段名称。当然,最好的方法是使用"Bulk"操作来实现最高效率

MongoDB 3.2或更新版

MongoDB 3.2弃用Bulk()及其关联的methods.您需要使用.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();

此查询产生与前一个查询相同的结果。

答案 2 :(得分:0)

感谢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);
    }
)

我很喜欢,因为源代码读取得很好,但是大量文档的性能很差。