【问题标题】:Update field type in mongo更新 mongo 中的字段类型
【发布时间】:2016-07-25 13:52:10
【问题描述】:

我在collection 中有大量记录:

{field: [value]}

我怎样才能有效地更新到:

{字段:值}

我尝试过这样的事情:(pymongo 语法)

collection.update({"field.1": {"$exists": True}},
                  {"$set": {'field': "field.1"}},
                  multi=True)

这显然不起作用。 由于大量记录,循环遍历每条记录并删除插入不是一种选择。

【问题讨论】:

    标签: python mongodb mongodb-query pymongo


    【解决方案1】:

    您需要循环游标并使用$set 更新运算符更新每个文档。当然,要做到这一点,您可以使用“批量”操作来获得最大效率。话虽如此,该方法会因您的 MongoDB 服务器版本和 PyMongo 版本而异。

    从 MongoDB 3.2 开始,您需要使用 Bulk Write OperationsbulkWrite() 方法。

    var requests = [];
    var cursor = db.collection.find( { "field.1": { "$exists": true } }, { "field": 1 } );
    cursor.forEach( document => { 
        requests.push({ 
            "updateOne": {
                "filter" : { "_id": document._id },
                "update" : { "field": { "$set": document.field[0] } }
            }
        });
        if (requests.length === 1000) {
            db.collection.bulkWrite(requests);
            requests = [];
        }
    });
    
    if (requests.length > 0) {
        db.collection.bulkWrite(requests);
    }
    

    此查询使用 PyMongo 3.0 驱动程序,提供您使用 bulk_write() 方法所需的内容:

    from pymongo import UpdateOne
    
    
    requests = [];
    cursor = db.collection.find({"field.1": {"$exists": True}}, {"field": 1})
    for document in cursor:
        requests.append(UpdateOne({'_id': document['_id']}, {'$set': {'field': document['field'][0]}}))
        if len(requests) == 1000:
            # Execute per 1000 operations
            db.collection.bulk_write(requests)
            requests = []
    if len(requests) > 0:
    
        # clean up queues
        db.collection.bulk_write(requests)
    

    从 MongoDB 2.6 开始,您需要使用现已弃用的 Bulk API。

    var bulk = db.collection.initializeUnorderedBulkOp();
    var count = 0;
    
    // cursor is the same as in the previous version using MongoDB 3.2
    cursor.forEach(function(document) { 
        bulk.find( { "_id": document._id } ).updateOne( { "$set": { "field": document.field[0] } } ); 
        count++;
        if (count % 1000 === 0) {
            bulk.execute();
            bulk = db.collection.initializedUnorderedBulkOp();
        }
    });
    
    // Again clean up queues
    if (count > 0 ) {
        bulk.execute();
    }
    

    翻译成 Python 给出以下内容。

    bulk = db.collection.initialize_unordered_bulk_op()
    count = 0
    
    for doc in cursor:
        bulk.find({'_id': doc['_id']}).update_one({'$set': {'field': doc['field'][0]}})
        count = count + 1
        if count == 1000:
            bulk.execute()
            bulk = db.collection.initialize_unordered_bulk_op()
    
    if count > 0:
        bulk.execute()
    

    【讨论】:

      【解决方案2】:

      如果您的数组只有一个元素,那么您的更新将不起作用,因为在 JavaScript(mongodb 深受其影响)the first array index is 0 中。这应该有效:

      collection.update({"field.0": {"$exists": True}},
                        {"$set": {'field': "field.0"}},
                        multi=True)
      

      【讨论】:

      • 现在所有field 值都会得到field.0 字符串值。
      • 这不是提问者想要做的吗?
      • Nono,field 将获得 field.0 文字字符串值,而不是来自 field 数组的第一项。
      • 是的,这对我有用,太好了,这是正确的答案,伙计们接受它。
      猜你喜欢
      • 1970-01-01
      • 2016-05-10
      • 2019-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多