35

MongoDB集約フレームワークでは、オブジェクト(つまり、JSONコレクション)で$unwind演算子を使用したいと考えていました。これは可能ではないようですが、回避策はありますか?これを実装する計画はありますか?

たとえば、集計ドキュメントから記事コレクションを取得します。ユーザー->評価からのマップである追加のフィールド「評価」があるとします。各ユーザーの平均評価を計算できますか?

これ以外に、私は集約フレームワークに非常に満足しています。

更新:これは、リクエストごとのJSONコレクションの簡略化されたバージョンです。ゲノムデータを保存しています。最も一般的なルックアップはランダムな人の遺伝子型を取得することであるため、遺伝子型を配列にすることはできません。

variants: [

    {
        name: 'variant1', 
        genotypes: {

            person1: 2,
            person2: 5,
            person3: 7,

        }
    }, 

    {
        name: 'variant2', 
        genotypes: {

            person1: 3,
            person2: 3,
            person3: 2,

        }
    }

]
4

4 に答える 4

32

集計フレームワークで説明しているタイプの計算を実行することはできません。これは、配列以外のメソッドがないためではありません。$unwindperson:value オブジェクトが配列内のドキュメントであったとしても、$unwind役に立ちません。

"group by" 機能 (MongoDB であろうとリレーショナル データベースであろうと) は、フィールドまたは列の値に対して実行されます。フィールドの値によってグループ化し、別のフィールドの値に基づいて合計/平均などを行います。

簡単な例は、あなたが提案したものの変形であり、例の記事コレクションに評価フィールドが追加されましたが、ユーザーから評価へのマップとしてではなく、次のような配列として:

{ title : title of article", ...
  ratings: [
         { voter: "user1", score: 5 },
         { voter: "user2", score: 8 },
         { voter: "user3", score: 7 }
  ]
}

これを次のように集約できます。

[ {$unwind: "$ratings"},
  {$group : {_id : "$ratings.voter", averageScore: {$avg:"$ratings.score"} } } 
]

しかし、あなたが説明したように構成されたこの例は、次のようになります。

{ title : title of article", ...
  ratings: {
         user1: 5,
         user2: 8,
         user3: 7
  }
}

またはこれさえ:

{ title : title of article", ...
  ratings: [
         { user1: 5 },
         { user2: 8 },
         { user3: 7 }
  ]
}

これができたとしても$unwind、ここで集計することは何もありません。考えられるすべてのキー (ユーザー) の完全なリストを把握していない限り、これで多くのことを行うことはできません。[*]

あなたが持っているものに類似したリレーショナルDBスキーマは次のようになります:

CREATE TABLE T (
   user1: integer,
   user2: integer,
   user3: integer
   ...
);

それは行われることではなく、代わりに次のようにします。

CREATE TABLE T (
   username: varchar(32),
   score: integer
);

次に、SQL を使用して集計します。

select username, avg(score) from T group by username;

将来的に集計フレームワークでこれを行うことができるようにする可能性のある MongoDB の拡張要求があります。一方、マップ/リデュースは常にあります。

[*] すべての一意のキーを知っている場合、これを行うには複雑な方法があります (これと同様の方法ですべての一意のキーを見つけることができます)。ただし、すべてのキーを知っている場合は、集計フレームワークが必要とする非常に複雑なdb.articles.find({"ratings.user1":{$exists:true}},{_id:0,"ratings.user1":1})予測を行うのではなく、単純にそれらを合計して平均することができます。

于 2012-07-08T17:12:46.057 に答える
11

3.4.4 以降、$objectToArray を使用してオブジェクトを配列に変換できます。

参照: https://docs.mongodb.com/manual/reference/operator/aggregation/objectToArray/

于 2017-09-28T21:20:03.323 に答える
1

これは古い質問ですが、試行錯誤の結果、人々が役立つと思われる情報に出くわしました。

パーサーを次のようにだますことで、実際にはダミーの値を巻き戻すことができます。

db.Opportunity.aggregate(
  { $project: {
        Field1: 1, Field2: 1, Field3: 1,
        DummyUnwindField: { $ifNull: [null, [1.0]] }
    }
  },
  { $unwind: "$DummyUnwindField" }
);

これにより、値が存在するかどうかに関係なく、ドキュメントごとに 1 行が生成されます。これをいじって、必要な結果を生成できる場合があります。これを複数の $unwinds と組み合わせて (map/reduce の emit() のように) したいと思っていましたが、残念ながら、最後の $unwind が勝つか、結合ではなく交差として結合し、結果を達成することができなくなります。探していました。集約フレームワークの機能には、私が使用したいと思っていた 1 つのユース ケースに適合しないため、残念ながらがっかりしています (そして、奇妙なことに、この分野の StackOverflow に関する多くの質問が尋ねているようです) - 一致に基づいて結果を並べ替えるレート。貧弱なマップ削減パフォーマンスを改善すると、この機能全体が不要になります。

于 2013-02-08T05:03:51.120 に答える