MongoDB集約フレームワークでは、オブジェクト(つまり、JSONコレクション)で$ unwind演算子を使用することを望んでいました。これは 可能 のように見えません、回避策はありますか?これを実装する計画はありますか?
たとえば、記事コレクションを集計 documentation から取得します。ユーザーからのマップである「評価」という追加のフィールドがあるとします->評価。各ユーザーの平均評価を計算できますか?
これ以外に、私は集約フレームワークに非常に満足しています。
更新:これは、リクエストごとのJSONコレクションの簡易バージョンです。ゲノムデータを保存しています。遺伝子型を配列にすることはできません。最も一般的な検索は、ランダムな人の遺伝子型を取得することです。
variants: [
{
name: 'variant1',
genotypes: {
person1: 2,
person2: 5,
person3: 7,
}
},
{
name: 'variant2',
genotypes: {
person1: 3,
person2: 3,
person3: 2,
}
}
]
_$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に対して実行します。これにより、すべての評価が返され、集計フレームワークが必要とする非常に複雑な予測を行うのではなく、単純に十分に合計および平均化できます。
3.4.4以降、$ objectToArrayを使用してオブジェクトを配列に変換できます
参照: https://docs.mongodb.com/manual/reference/operator/aggregation/objectToArray/
これは古い質問ですが、人々が有用だと思うかもしれない試行錯誤を通して、ちょっとした情報に出くわしました。
次のようにパーサーをだますことにより、ダミー値でくつろぐことが実際に可能です。
db.Opportunity.aggregate(
{ $project: {
Field1: 1, Field2: 1, Field3: 1,
DummyUnwindField: { $ifNull: [null, [1.0]] }
}
},
{ $unwind: "$DummyUnwindField" }
);
これにより、値が存在するかどうかに関係なく、ドキュメントごとに1行が生成されます。これをいじくり回して、必要な結果を生成することができます。私はこれを複数の$ unwindsと組み合わせて(map/reduceの排出のような)望んでいましたが、残念ながら、最後の$ unwindが勝つか、ユニオンではなく交差として結合するため、結果を達成できません。探していました。集計フレームワークの機能は、私がそれを使用することを望んでいた1つのユースケースに適合しないため、残念なことに失望しています(奇妙なことに、この領域のStackOverflowに関する多くの質問が尋ねているようです)-一致に基づく結果の順序付け割合。不十分なマップのパフォーマンスを低下させると、この機能全体が不要になります。
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);