次の回答では、コレクション全体で 5 つの回答を持つ単純なデータ セットを使用しています。
> db.foo.find()
{ "_id" : ObjectId("4fba6b0c7c32e336fc6fd7d2"), "replies" : [ 1, 2, 3 ] }
{ "_id" : ObjectId("4fba6b157c32e336fc6fd7d3"), "replies" : [ 1, 2 ] }
単純にドキュメントを数えているわけではないので、ここではdb.collection.count()は役に立ちません。MapReduceを使用して各ドキュメントをスキャンし、応答配列の長さを集計する必要があります。次の点を考慮してください。
db.foo.mapReduce(
function() { emit('totalReplies', { count: this.replies.length }); },
function(key, values) {
var result = { count: 0 };
values.forEach(function(value) {
result.count += value.count;
});
return result;
},
{ out: { inline: 1 }}
);
map 関数 (最初の引数) はコレクション全体で実行され、一定のキーの下で各ドキュメントの返信数を出力します。Mongo は、出力されたすべての値を考慮し、reduce 関数 (2 番目の引数) を何度も実行して、結果を統合 (文字通り削減) します。うまくいけば、ここのコードは簡単です。map/reduce を初めて使用する場合、reduce メソッドは独自の出力を処理できる必要があることに注意してください。これについては、上記のリンクにある MapReduce ドキュメントで詳しく説明されています。
注: コレクションが非常に大きい場合は、別の出力モード (コレクション出力など) を使用する必要がある場合があります。ただし、inline
小さなデータ セットには適しています。
最後に、MongoDB 2.1 以降を使用している場合は、Aggregation Frameworkを利用して JS 関数の記述を回避し、これをさらに簡単にすることができます。
db.foo.aggregate(
{ $project: { replies: 1 }},
{ $unwind: "$replies" },
{ $group: {
_id: "result",
totalReplies: { $sum: 1 }
}}
);
ここで 3 つのことが起こっています。まず、その分野に興味があることを Mongo に伝えreplies
ます。次に、射影のフィールド全体ですべての要素を反復処理できるように、配列を巻き戻したいと考えています。最後に、「結果」バケットの下で結果を集計し (任意の定数で構いません)、各反復1
の結果に追加します。totalReplies
このクエリを実行すると、次の結果が得られます。
{
"result" : [{
"_id" : "result",
"totalReplies" : 5
}],
"ok" : 1
}
上記の回答は Mongo クライアントに関して書きましたが、問題なく PHP に変換できます。PHP ドライバーには現在、どちらのヘルパー メソッドもないため、 MongoDB::command()を使用して MapReduce または集計クエリを実行する必要があります。現在、PHP ドキュメントに MapReduce の例があり、この Google グループの投稿を参照して、同じ方法で集計クエリを実行できます。