【发布时间】:2018-07-15 16:14:53
【问题描述】:
我有一个现有的集合,其中包含近 100 万个文档,现在我想在这个集合中附加一个新的字段数据。 (我正在使用 PyMongo)
例如,我现有的集合db.actions 看起来像:
...
{'_id':12345, 'A': 'apple', 'B': 'milk'}
{'_id':12346, 'A': 'pear', 'B': 'juice'}
...
现在我想将一个新的列字段数据附加到这个现有的集合中:
...
{'_id':12345, 'C': 'beef'}
{'_id':12346, 'C': 'chicken'}
...
这样生成的集合应如下所示:
...
{'_id':12345, 'A': 'apple', 'B': 'milk', 'C': 'beef'}
{'_id':12346, 'A': 'pear', 'B': 'juice', 'C': 'chicken'}
...
我知道我们可以用 update_one 和 for 循环来做到这一点,例如
for doc in values:
collection.update_one({'_id': doc['_id']},
{'$set': {k: doc[k] for k in fields}},
upsert=True
)
其中values 是一个字典列表,每个字典包含两项,_id 键值对和新字段键值对。 fields 包含我想添加的所有新字段。
但是,问题是我有一百万个文档要更新,任何带有for 循环的东西都太慢了,有没有办法更快地附加这个新字段?类似于insert_many 的东西,除了它附加到现有集合?
================================================
更新1:
这就是我现在所拥有的,
bulk = self.get_collection().initialize_unordered_bulk_op()
for doc in values:
bulk.find({'_id': doc['_id']}).update_one({'$set': {k: doc[k] for k in fields} })
bulk.execute()
我首先使用insert_many将示例数据框写入数据库,性能:
Time spent in insert_many: total: 0.0457min
然后我使用update_one 和bulk 操作将额外的两个字段添加到集合中,我得到:
Time spent: for loop: 0.0283min | execute: 0.0713min | total: 0.0996min
更新2:
我在现有集合和新列数据中都添加了一个额外的列,目的是使用左连接来解决这个问题。如果您使用左连接,则可以忽略 _id 字段。
例如,我现有的集合db.actions 看起来像:
...
{'A': 'apple', 'B': 'milk', 'dateTime': '2017-10-12 15:20:00'}
{'A': 'pear', 'B': 'juice', 'dateTime': '2017-12-15 06:10:50'}
{'A': 'orange', 'B': 'pop', 'dateTime': '2017-12-15 16:09:10'}
...
现在我想将一个新的列字段数据附加到这个现有的集合中:
...
{'C': 'beef', 'dateTime': '2017-10-12 09:08:20'}
{'C': 'chicken', 'dateTime': '2017-12-15 22:40:00'}
...
这样生成的集合应如下所示:
...
{'A': 'apple', 'B': 'milk', 'C': 'beef', 'dateTime': '2017-10-12'}
{'A': 'pear', 'B': 'juice', 'C': 'chicken', 'dateTime': '2017-12-15'}
{'A': 'orange', 'B': 'pop', 'C': 'chicken', 'dateTime': '2017-12-15'}
...
【问题讨论】:
-
见
db.collection.initializeUnorderedBulkOp()docs.mongodb.com/manual/reference/method/… -
@Saravana 为此,我认为我仍然需要执行 for 循环来创建
bulk.updates,然后运行 execute。我已经比较了使用bulk和execute与insert,但它仍然比insert_many慢得多,我希望得到类似insert_many的性能。 -
您不能简单地为具有 $addfields 阶段的聚合创建一个管道阶段,然后使用类似
db.mydb.values.aggregate(pipeline)的东西运行它吗? -
@MichaëlvanderHaven 我会尝试研究一下(我对 MongoDB 有点陌生,仍然熟悉它的命令等),
-
用于在聚合框架中使用 python 调用设置管道:api.mongodb.com/python/current/examples/aggregation.html 对于
$addfields阶段,请看这里:docs.mongodb.com/manual/reference/operator/aggregation/…