38

各ドキュメントが次の構造を持つユーザーのコレクションがあります。

{
  "_id": "<id>",
  "login": "xxx",
  "solved": [
    {
      "problem": "<problemID>",
      "points": 10
    },
    ...
  ]
}

フィールドsolvedは空であるか、任意の数のサブドキュメントを含む可能性があります。私の目標は、ユーザーのリストと、points問題をまだ解決していないユーザーに合計スコア0が割り当てられる合計スコア(合計)を取得することです。これは、単一のクエリでこれを行うことができますか(理想的には集計を使用)フレームワーク)?

集計フレームワークで次のクエリを使用しようとしました:

{ "$group": {
  "_id": "$_id",
  "login": { "$first": "$login" },
  "solved": { "$addToSet": { "points": 0 } }
} }
{ "$unwind": "$solved" }
{ "$group": {
  "_id": "$_id",
  "login": { "$first": "$login" },
  "solved": { "$sum": "$solved.points" }
} }

ただし、次のエラーが発生します。

exception: The top-level _id field is the only field currently supported for exclusion

前もって感謝します

4

3 に答える 3

117

MongoDB 3.2 バージョン以降では、$unwindオペレーターにいくつかのオプションがあり、特にpreserveNullAndEmptyArraysオプションがこれを解決します。

このオプションが true に設定されていて、パスが null、見つからない、または空の配列である$unwind場合、ドキュメントが出力されます。false の$unwind場合、パスが null、欠落、または空の配列の場合、ドキュメントは出力されません。あなたの場合、それをtrueに設定してください:

db.collection.aggregate([
    { "$unwind": {
        "path": "$solved",
        "preserveNullAndEmptyArrays": true
    } },
    { "$group": {
        "_id": "$_id",
        "login": { "$first": "$login" },
        "solved": { "$sum": "$solved.points" }
    } }
])
于 2016-05-24T08:32:07.330 に答える
8

解決策は次のとおりです。「解決済み」フィールドが存在しないか、null に等しいか、解決済みの問題とスコアの配列があると想定しています。それが処理しないケースは、空の配列である「解決済み」ですが、それは追加できる簡単な追加調整になります。

project = {$project : {
        "s" : {
            "$ifNull" : [
                "$solved",
                [
                    {
                        "points" : 0
                    }
                ]
            ]
        },
        "login" : 1
    }
};
unwind={$unwind:"$s"};
group= { "$group" : {
        "_id" : "$_id",
        "login" : {
            "$first" : "$login"
        },
        "score" : {
            "$sum" : "$s.points"
        }
    }
}

db.students.aggregate( [ project, unwind, group ] );

于 2012-12-16T04:14:59.623 に答える