2012-03-14 178 views
43

我有一组像这样保存子集另一个集合

{date: 20120101} 
{date: 20120103} 
{date: 20120104} 
{date: 20120005} 
{date: 20120105} 

我如何保存日期“20120105”到另一个收集这些文件的一个子集?

db.subset.save(db.full_set.find({date: "20120105"}));

回答

46

这里的外壳版本:

db.full_set.find({date:"20120105"}).forEach(function(doc){ 
    db.subset.insert(doc); 
}); 

注:由于MongoDB的2.6,聚合框架能够更快地做到这一点;细节见黑人的答案。

+5

从[2.2]开始(http://docs.mongodb.org/manual/reference/method/db.collection.insert/),insert可以接受一系列文档,因此您可以执行'var docs =。 。..find(...)指定者(); db.coll.insert(文档)'。尽管 – 2013-03-01 02:58:45

+1

不幸,[$ out](https://docs.mongodb.org/manual/reference/operator/aggregation/out/)自从版本2.6 [ ](https://docs.mongodb.org/manual/release-notes/2.6/),而不是[2.2](https://docs.mongodb.org/manual/release-notes/2。2 /) – CroWell 2015-11-11 11:01:31

4

有SQL的insert into ... select from ...没有直接的等价物。

你必须自己照顾它。获取感兴趣的文档并将其保存到另一个集合中。

你可以在shell中做到这一点,但我会在Ruby中使用一个小的外部脚本。事情是这样的:

require 'mongo' 

db = Mongo::Connection.new.db('mydb') 

source = db.collection('source_collection') 
target = db.collection('target_collection') 

source.find(date: "20120105").each do |doc| 
    target.insert doc 
end 
13

实际上,在MongoDB中有一个等效的SQL insert into ... select from。首先,您将多个文档转换为文档数组;那么您将数组到目标集合

db.subset.insert(db.full_set.find({date:"20120105"}).toArray()) 
64

作为一个新的解决方案,我会建议使用聚合框架问题:

db.full_set.aggregate([ { $match: { date: "20120105" } }, { $out: "subset" } ]);

它比的forEach快大约100倍,至少在我的情况。这是因为整个聚合管道在mongod进程中运行,而基于find()insert()的解决方案必须将所有文档从服务器发送到客户端,然后再发回。即使服务器和客户端在同一台计算机上,性能也会受到影响。

+0

只是考虑到如果聚合结果超过最大文档大小(16MB),将会失败 – c24b 2015-05-19 15:19:12

+5

$ out对文档大小没有通常的限制,因为您正在写入集合 – Kyrstellaine 2015-05-29 22:31:16

+0

进一步的证据:我只是与我自己的数据进行比较,聚合速度比forEach快大约50倍。我还比较了mapreduce,聚合速度快了大约5倍。 – Luke 2016-02-09 15:35:27

7

最通用的解决方案是这样的:

制作使用(由@melan给出的答案)的聚合:

db.full_set.aggregate({$match:{your query here...}},{$out:"sample"}) 
db.sample.copyTo("subset") 

在有手术前的“子集”文件,这甚至工作你想保留那些“旧”的文档,只是插入一个新的子集。

必须小心,因为copyTo()命令用相同的_id替换文档。

+0

copyTo的解释是非常有用的补充。 – TheDude 2017-06-15 15:02:58