在MongoDB中,如何查找大型分片集合的不同值?

时间:2016-09-29 18:27:15

标签: python mongodb-query

我有一个大型的mongodb系列:

  • 有3个碎片,
  • 总计300M记录(至少)
  • 分片键是(field1:1,field2:1)
  • 还有其他非索引字段。
  • Field1是一个~200个字符的字符串
  • Field2是一个int。
  • Field1有大约10M个不同的值,并且总是添加更多。

第1部分:DISTINCT VALUES

我需要找到field1的所有不同值。

调用db.myCollection.distinct(" field1")失败,因为结果集中的数据超过16MB。

由于分片键是索引,因此应该是一个覆盖查询。

第2部分:返回已分类的结果

假设有上述答案,我希望从故障中恢复,即按排序顺序返回结果。这不重要。

排序输出的目标:如果查询中途失败,我可以通过添加field1:{$ gt:lastGoodValue}的查询说明符从我停止的地方继续。

所以:这可能吗?简单?我必须聚合或map-reduce吗?目前,我正在迭代所有300M记录,并且不必要地推送了大量数据。

1 个答案:

答案 0 :(得分:1)

集合distinct命令(doc link)返回单个变量,即数组。此变量作为BSON文档发送,在MongoDB中具有16MB的最大大小限制。

将结果集放在数组中对于某些情况很方便,但如果它不能确保适合16MB那么你将无法使用它,正如你所发现的那样。

第1部分回答

相反,您可以retrieve distinct values在聚合命令中使用$ group阶段。您也可以使用MapReduce,但聚合具有更好的性能,因此我将重点关注它。

db.myCollectoin.aggregate( [ { $group : { _id : "$myField" } } ] )

这会将单个数组变量的结果更改为游标,与普通查询/查找命令相同。因此,您在客户端迭代不同值的方式会有所不同,但您可以继续获取越来越多的值,直到光标结束。

使用相同的命令,无论您是拥有群集,副本集还是独立的mongod。一个重要的性能考虑因素是明确分组的字段是否已编入索引,但正如您所提到的,该字段是分片键中的前导字段,我们知道它是。

第2部分回答

是的,你可以对它进行排序。在$ group之后添加$ sort阶段。

db.myCollection.aggregate( [ 
  { $group : { _id : "$myField" } }, 
  { $sort: { "_id": 1 } } 
] )

如果必须从某一点再次重新启动查询,则应添加$match stage作为聚合管道中的第一个操作。例如。 { $match: {"myField": { "$gt": "AbCdEf...."} } },

请注意新的聚合用户 :$ sort阶段中的第二个“_id”是$ group阶段输出的“_id”字段,即不同的“myField”值。它不是基础集合中“_id”值的排序。

如果您愿意,可以使用$ project阶段重命名该中间阶段的“_id”键名称。

db.myCollection.aggregate( [ 
  { $group : { _id : "$myField" } }, 
  { $project : { 
     "_id" : false, /*stop it appearing as "_id" */
     "myField" : "$_id" /*put original field name "myField" back on*/
  } }, 
  { $sort: { "myField": 1 } } 
] )