web-dev-qa-db-ja.com

$集計フレームワークでオブジェクトを巻き戻す

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

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

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

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

variants: [

    {
        name: 'variant1', 
        genotypes: {

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

        }
    }, 

    {
        name: 'variant2', 
        genotypes: {

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

        }
    }

]
30
Brett Thomas

_$unwind_メソッドがないため、集計フレームワークで記述しているタイプの計算を行うことはできません-そしてnotです非配列。 person:valueオブジェクトが配列内のドキュメントであったとしても、_$unwind_は役に立ちません。

「グループ化」機能(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には、将来、集約フレームワークでこれを実行できるようにする拡張要求があります。値をキーに射影して、その逆を行う機能です。その間、常にmap/reduceがあります。

[*]一意のキーをすべて知っている場合( this と同様の方法ですべての一意のキーを見つけることができます)、これを行うには複雑な方法がありますが、すべてのキーを知っている場合は、 db.articles.find({"ratings.user1":{$exists:true}},{_id:0,"ratings.user1":1})形式の一連のクエリを各userXに対して実行します。これにより、すべての評価が返され、集計フレームワークが必要とする非常に複雑な予測を行うのではなく、単純に十分に合計および平均化できます。

29
Asya Kamsky

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

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

7
Adrian

これは古い質問ですが、人々が有用だと思うかもしれない試行錯誤を通して、ちょっとした情報に出くわしました。

次のようにパーサーをだますことにより、ダミー値でくつろぐことが実際に可能です。

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

これにより、値が存在するかどうかに関係なく、ドキュメントごとに1行が生成されます。これをいじくり回して、必要な結果を生成することができます。私はこれを複数の$ unwindsと組み合わせて(map/reduceの排出のような)望んでいましたが、残念ながら、最後の$ unwindが勝つか、ユニオンではなく交差として結合するため、結果を達成できません。探していました。集計フレームワークの機能は、私がそれを使用することを望んでいた1つのユースケースに適合しないため、残念なことに失望しています(奇妙なことに、この領域のStackOverflowに関する多くの質問が尋ねているようです)-一致に基づく結果の順序付け割合。不十分なマップのパフォーマンスを低下させると、この機能全体が不要になります。

0
saarp

これは私が見つけて拡張したものです

mongoに実験用データベースを作成します

db.copyDatabase('livedb' , 'experimentdb')

さて、experimentdbを使用し、experimentcollectionで配列をオブジェクトに変換します

db.getCollection('experimentcollection').find({}).forEach(function(e){
    if(e.store){
        e.ratings = [e.ratings]; //Objects name to be converted to array eg:ratings
        db.experimentcollection.save(e);
    }
})

jsonをフラットオブジェクトに変換するいくつかのオタクjsコード

var flatArray = [];

var data = db.experimentcollection.find().toArray();

for (var index = 0; index < data.length; index++) {

  var flatObject = {};

  for (var prop in data[index]) {

    var value = data[index][prop];

    if (Array.isArray(value) && prop === 'ratings') {
      for (var i = 0; i < value.length; i++) {
        for (var inProp in value[i]) {
          flatObject[inProp] = value[i][inProp];
        }
      }
    }else{
        flatObject[prop] = value;
    }
  }
  flatArray.Push(flatObject);
}

printjson(flatArray);
0
vijay