8

Mongooseを使用して、コレクション内の配列内の文字列の出現回数をカウントしようとしています。私の「スキーマ」は次のようになります。

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

私の目的は、ドキュメントごとに複数の値を含めることができる「Thing」コレクションの上位10個の「トークン」を取得することです。例えば:

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を使用することを検討していますが、どのオプションが最適かわかりません。

4

1 に答える 1

23

ああ、私は解決策を見つけました。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 ]
});

約200,000レコードにわたる予備テストでは、MapReduceよりも著しく高速であるため、スケーリングが向上する可能性がありますが、これはざっと見ただけです。YMMV。

于 2013-02-05T19:58:14.823 に答える