【问题标题】:How to unset all fields except some known fields?如何取消设置除某些已知字段外的所有字段?
【发布时间】:2016-07-01 01:26:39
【问题描述】:

我需要删除文档的某些字段,但我只知道我想保留的字段。我如何 $unset 除了我的已知字段之外的所有字段。例如:

我的数据库中的文档如下所示

{ 
  "_id" : ObjectId("1234567891234"),
  "name" : "testname",
  "settings" : {
    "pairing" : true}
  "subject" : "alarm"
}

我想删除“设置”和“主题”字段。所以它会像下面这样。

{
  "_id" : ObjectId("1234567891234"),
  "name" : "testname"
}

但是我不能只对字段使用“$unset”,因为我只知道我想保留的字段。

有没有办法在 pymongo 中做到这一点。我发现了一个相关的问题,但我不知道这在 python 2.7 中是否可行。

相关问题: How do I unset all fields except a known set of fields?

【问题讨论】:

  • 是的,这是可能的。我还添加了对该问题的答案,以展示如何在 shell 中执行此操作。

标签: python mongodb python-2.7 mongodb-query pymongo


【解决方案1】:

一种可能的方法是在没有“$set”的情况下进行更新,这样它将更新整个文档,删除未指定的字段,例如:

{ 
  "_id" : ObjectId("1234567891234"),
  "name" : "testname",
  "settings" : {
    "pairing" : true}
  "subject" : "alarm"
}

在做

db.collection_name.update({"_id" : ObjectId("1234567891234")},{"name" : "testname"})

将导致其他字段被删除,但 “名称”。 所以在python中你可以做到以下几点:

result = db.collection_name.find_one({"name":"testname"})

(如果您知道可以搜索的 ID,但请务必导入 from bson.objectid import ObjectId)。之后,您将集合存储在结果中。那么你想用你知道的记录来更新例如:

db.collection_name.update_one({"_id":result["_id"]},{"name":result["name"]})

这是一种方法。当然,它只会保留“name”和“_id”,但所有其他未指定的字段都将被删除。希望对你有帮助

【讨论】:

    【解决方案2】:

    是的,这是可能的!如果要取消设置集合中多个文档的 已知 字段以外的所有字段,最好的方法是使用“批量”操作。

    MongoDB 3.2 弃用了 Bulk() 及其相关方法。所以如果你应该使用.bulk_write()

    from itertools import zip_longest # or izip_longest in Python 2.x
    from pymongo import MongoClient, UpdateOne
    
    
    client = MongoClient()
    db = client.db
    collection = db.collection
    requests = []
    fields = ['name', '_id']
    for document in collection.find():
        unset_op = dict(zip_longest(set(document.keys()).difference(fields), [''], fill_value='')) 
        requests.append(UpdateOne({'_id': document['_id']}, {'$unset': unset_op}))
        # Execute per 1000 operations and re-init.
        if len(requests) == 1000:
            collection.bulk_write(requests)
            requests = []
    
    # clean up the queues
    if requests:
        collection.bulk_write(requests)
    

    对于单个文档,您需要使用 find_one 方法返回与您的条件匹配的文档,然后使用 3.0 版中的 replace_one 新方法

    document = collection.find_one({'_id': 111})
    collection.replace_one({'_id': document['_id']}, dict(zip(fields, [document[field] for field in fields])))
    

    如果您使用的不是最新版本的 MongoDB 或 Pymongo 驱动程序,则需要使用Bulk() API。

    bulk = collection.initialize_unordered_bulk_op()
    count = 0
    for document in collection.find():
        unset_op = dict(zip_longest(set(document.keys()).difference(fields), [''], fill_value=''))
        bulk.find({'_id': document['_id']}).update_one({'$unset': unset_op})
        count = count + 1
        if count % 1000 == 0:
            bulk.execute()
            bulk = collection.initialize_unordered_bulk_op()        
        if count > 0:
            bulk.execute()
    

    对于单个文档,您可以依赖 update_one 方法。

    unset_op = dict(izip_longest(set(document.keys()).difference(fields), [''], fill_value=''))
    collection.update_one({'_id': document['_id']}, {'$unset': unset_op})
    

    【讨论】:

      猜你喜欢
      • 2023-03-11
      • 2020-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多