web-dev-qa-db-ja.com

配列内部要素によるMongoDBグループ

記事のリストがあり、各記事には、言及されているさまざまな個人をリストする配列プロパティがあります。

_id: {
    $oid: "52b632a9e4f2ba13c82ccd23"
},
providerName: "The Guardian",
url: "http://feeds.theguardian.com/c/34708/f/663860/s/3516cebc/sc/38/l/0L0Stheguardian0N0Cmusic0C20A130Cdec0C220Cwaterboys0Efishermans0Eblues0Etour0Ehammersmith/story01.htm",
subject: "The Waterboys – review",
class_artist: [
    "paul mccartney"
]

私は、過去7日間にタグ付けされた記事の数に基づいて、個々のすべてのアーティスト(class_artist)のリストを取得しようとしました(失敗しました)。

私は次のようになりました:

var date = new Date();
date.setDate(date.getDate() - 7);

db.articles.group({
    key: { class_artist: 1 },
    cond: { class_date: { $gt: date } },
    reduce: function ( curr, result ) { result.cnt++; },
    initial: { cnt : 0 }
}).sort({cnt: -1});

しかし、残念なことに、個々の配列値に基づいてカウントされるのではなく、配列の構成(つまり、アーティストのリスト)によってカウントされます。

$unwind関数を使用しようとしましたが、機能させることができませんでした。

36
Gil Adirim

どのフレームワークを使用していますか?これはMongoDBシェルではなく、 MapReduce の奇妙なラッパーのように見えます。その場合、 $ unwind は使用できず、 集約フレームワーク のユーザーに必要です。 mongoシェルに必要なものは次のとおりです。

db.articles.aggregate([
  {$match: { class_date: { $gte: date } } },
  {$project: { _id: 0, class_artist: 1 } },
  {$unwind: "$class_artist" },
  {$group: { _id: "$class_artist", tags: { $sum: 1 } }},
  {$project: { _id: 0,class_artist: "$_id", tags: 1 } },
  {$sort: { tags: -1 } }
])

とても効率的:

  1. フィルター 過去7日間に既に変数を設定しているため、日付で
  2. プロジェクト 必要なフィールドのみ{1つだけ必要です! }
  3. nwind 配列なので、すべてのドキュメントのすべての配列要素のレコードがあります
  4. グループ 展​​開されたドキュメントのアーティスト
  5. _idで混乱したグループとして使用できるドキュメント形式に投影する
  6. 並べ替え 結果を逆順に表示して、先頭のタグが最初に表示される

集約の素晴らしい点は、これらの段階を徐々に構築して、何が起こっているのかを確認できることです。

必要に応じて、独自のドライバー実装またはODMフレームワークをシェイクしてベイクします。

109
Neil Lunn