Mongoose / MongoDB:计算数组中的元素数量

10

我正在尝试使用Mongoose来计算我的集合中数组中一个字符串出现的次数。我的“schema”看起来像这样:

var ThingSchema = new Schema({
  tokens: [ String ]
});

我的目标是获取“Thing”集合中前10个“tokens”,其中每个文档可以包含多个值。例如:

var documentOne = {
    _id: ObjectId('50ff1299a6177ef9160007fa')
  , tokens: [ 'foo' ]
}

var documentTwo = {
    _id: ObjectId('50ff1299a6177ef9160007fb')
  , tokens: [ 'foo', 'bar' ]
}

var documentThree = {
    _id: ObjectId('50ff1299a6177ef9160007fc')
  , tokens: [ 'foo', 'bar', 'baz' ]
}

var documentFour = {
    _id: ObjectId('50ff1299a6177ef9160007fd')
  , tokens: [ 'foo', 'baz' ]
}

...会给我数据结果:

[ foo: 4, bar: 2 baz: 2 ]

我正在考虑在这个工具中使用MapReduce和Aggregate,但我不确定哪个是最好的选择。


除非您希望将结果保留在自己的集合中,否则请使用aggregate。您需要查看$unwind操作符来实现这一点。 - JohnnyHK
到目前为止,Mongoose的mapReduce类已经将临时操作符添加到查询中,允许返回结果集而不是持久化。除此之外,我是否有使用aggregate的原因? - Eric Martindale
1
“聚合”通常会快得多。 - JohnnyHK
1
聚合框架是专门为处理这类查询(通过map-reduce)而编写的。我无法说它有多高的性能,但聚合查询具有更高的性能和更低的复杂性是其设计目的。聚合使用C++,而Map-Reduce使用(性能较低的)JavaScript [请参见幻灯片](http://www.10gen.com/presentations/mongosv-2011/mongodbs-new-aggregation-framework) - numbers1311407
1个回答

25

啊哈,我找到了解决方案。MongoDB的aggregate框架允许我们在集合上执行一系列任务。特别值得注意的是$unwind,它将文档中的数组拆分为唯一文档,因此它们可以被大规模地分组/计数。

MongooseJS非常方便地在模型上公开了这一功能。使用上面的示例,代码如下:

Thing.aggregate([
    { $match: { /* Query can go here, if you want to filter results. */ } } 
  , { $project: { tokens: 1 } } /* select the tokens field as something we want to "send" to the next command in the chain */
  , { $unwind: '$tokens' } /* this converts arrays into unique documents for counting */
  , { $group: { /* execute 'grouping' */
          _id: { token: '$tokens' } /* using the 'token' value as the _id */
        , count: { $sum: 1 } /* create a sum value */
      }
    }
], function(err, topTopics) {
  console.log(topTopics);
  // [ foo: 4, bar: 2 baz: 2 ]
});

在初步测试中,相比MapReduce,它明显更快,大约涵盖了20万条记录,并且很可能更好地扩展,但这只是一个粗略的瞥见。你的情况可能会有所不同(YMMV)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接