1

与えられたコレクションmdの抽象的なドキュメント:

{
    vals : [{
        uid : string,
        val : string|array
    }]
}

次の、部分的に正しい集計が行われます。

db.md.aggregate(
    { $unwind : "$vals" },
    { $match : { "vals.uid" : { $in : ["x", "y"] } } },
    {
        $group : { 
            _id : { uid : "$vals.uid" },
            vals : { $addToSet : "$vals.val" }

        }
    }
);

次の結果につながる可能性があります。

"result" : [
    {
        "_id" : {
            "uid" : "x"
        },
        "vals" : [
            [
                "24ad52bc-c414-4349-8f3a-24fd5520428e",
                "e29dec2f-57d2-43dc-818a-1a6a9ec1cc64"
            ],
            [
                "5879b7a4-b564-433e-9a3e-49998dd60b67",
                "24ad52bc-c414-4349-8f3a-24fd5520428e"
            ]
        ]
    },
    {
        "_id" : {
            "uid" : "y"
        },
        "vals" : [
            "0da5fcaa-8d7e-428b-8a84-77c375acea2b",
            "1721cc92-c4ee-4a19-9b2f-8247aa53cfe1",
            "5ac71a9e-70bd-49d7-a596-d317b17e4491"
        ]
    }
]

xは文字列ではなく配列を含むドキュメントに集約された結果であるため、結果のvalsは配列の配列です。この場合に私が探しているのは、(yの結果のように)フラット化された配列を持つことです。

私にとっては、1回の集約呼び出しだけで達成したいことは、現在、特定の操作ではサポートされていないようです。たとえば、型変換を実行できないか、すべての場合に入力型として配列をアンワインドする必要があります。

マップリデュースは私が持っている唯一のオプションですか?そうでない場合...ヒントはありますか?

ありがとう!

4

2 に答える 2

3

集計を使用して、スキーマを変更せずに必要な計算を実行できます (ただし、このフィールドのクエリと集計を簡単に記述できるようにするためだけにスキーマを変更することを検討することもできます)。

読みやすくするために、パイプラインを複数のステップに分割しました。また、読みやすくするために、ドキュメントを少し簡略化しました。

サンプル入力:

> db.md.find().pretty()
{
    "_id" : ObjectId("512f65c6a31a92aae2a214a3"),
    "uid" : "x",
    "val" : "string"
}
{
    "_id" : ObjectId("512f65c6a31a92aae2a214a4"),
    "uid" : "x",
    "val" : "string"
}
{
    "_id" : ObjectId("512f65c6a31a92aae2a214a5"),
    "uid" : "y",
    "val" : "string2"
}
{
    "_id" : ObjectId("512f65e8a31a92aae2a214a6"),
    "uid" : "y",
    "val" : [
        "string3",
        "string4"
    ]
}
{
    "_id" : ObjectId("512f65e8a31a92aae2a214a7"),
    "uid" : "z",
    "val" : [
        "string"
    ]
}
{
    "_id" : ObjectId("512f65e8a31a92aae2a214a8"),
    "uid" : "y",
    "val" : [
        "string1",
        "string2"
    ]
}

パイプラインの段階:

> project1 = {
    "$project" : {
        "uid" : 1,
        "val" : 1,
        "isArray" : {
            "$cond" : [
                {
                    "$eq" : [
                        "$val.0",
                        [ ]
                    ]
                },
                true,
                false
            ]
        }
    }
}
> project2 = {
    "$project" : {
        "uid" : 1,
        "valA" : {
            "$cond" : [
                "$isArray",
                "$val",
                [
                    null
                ]
            ]
        },
        "valS" : {
            "$cond" : [
                "$isArray",
                null,
                "$val"
            ]
        },
        "isArray" : 1
    }
}
> unwind = { "$unwind" : "$valA" }
> project3 = {
    "$project" : {
        "_id" : 0,
        "uid" : 1,
        "val" : {
            "$cond" : [
                "$isArray",
                "$valA",
                "$valS"
            ]
        }
    }
}

最終集計:

> db.md.aggregate(project1, project2, unwind, project3, group)
{
    "result" : [
        {
            "_id" : "z",
            "vals" : [
                "string"
            ]
        },
        {
            "_id" : "y",
            "vals" : [
                "string1",
                "string4",
                "string3",
                "string2"
            ]
        },
        {
            "_id" : "x",
            "vals" : [
                "string"
            ]
        }
    ],
    "ok" : 1
}
于 2013-02-28T14:40:38.187 に答える
0

常に "vals.val" フィールドを配列フィールドとして使用してスキーマを変更する場合 (レコードに要素が 1 つしか含まれていない場合でも)、次のように簡単に変更できます。

db.test_col.insert({
    vals : [
        {
            uid : "uuid1",
            val : ["value1"]
        },
        {
            uid : "uuid2",
            val : ["value2", "value3"]
        }]
    });
db.test_col.insert(
    {
        vals : [{
            uid : "uuid2",
            val : ["value4", "value5"]
        }]
    });

このアプローチを使用すると、2 つの $unwind 操作を使用するだけで済みます。1 つは「親」配列を巻き戻し、2 つ目はすべての「vals.val」値を巻き戻します。したがって、次のようにクエリします

db.test_col.aggregate(
    { $unwind : "$vals" },
    { $unwind : "$vals.val" },
    {
        $group : { 
            _id : { uid : "$vals.uid" },
            vals : { $addToSet : "$vals.val" }
        }
    }
);

期待値を取得できます。

{
    "result" : [
        {
            "_id" : {
                "uid" : "uuid2"
            },
            "vals" : [
                "value5",
                "value4",
                "value3",
                "value2"
            ]
        },
        {
            "_id" : {
                "uid" : "uuid1"
            },
            "vals" : [
                "value1"
            ]
        }
    ],
    "ok" : 1
}

いいえ、フィールドが配列フィールドでない場合に $unwind が失敗するため、現在のスキーマを使用してこのクエリを実行することはできません。

于 2013-02-25T23:36:02.643 に答える