0

「アカウント」コレクションにドキュメントがあります。一部のフィールドは宣言されていない場合があります。これを見てください。

{ _id: ObjectId(1), price: 5400, product: ObjectId(2), count: 1            }
{ _id: ObjectId(1),              product: ObjectId(2), count: 0, sale: 0.2 }
{ _id: ObjectId(1),              product: ObjectId(2), count: 1            }

集計フレームワークを使用して、製品の最終価格、最終販売、カウントを取得したいと考えています。現在、私はこのクエリを使用しています

db.collection('account').aggregate([
{
    $group: {
            _id: '$product',
            count: { $sum: '$count' },
            price: { $last: '$price' }, 
            sale: { $last: '$sale' }
        }
    }
], { allowDiskUse: true }).toArray()

しかしsalepriceフィールドは になりnullます。$projectbeforeを使用する必要があると思いますが、$group現在のフィールドが null の場合、最後のドキュメントの値を保持するにはどうすればよいですか?

4

2 に答える 2

2

解決策
次のパイプラインにより、目的の結果が得られるはずです

db.getCollection('account').aggregate(
[
    {
        $project: {
            _id: '$product',
            fields: [
                { name: { $literal: 'price' }, value: '$price',        count: { $literal: 0 } },
                { name: { $literal: 'sale' },  value: '$sale',         count: { $literal: 0 } },
                { name: { $literal: 'count' }, value: { $literal: 0 }, count: '$count' }
            ]
        }
    },
    {
        $unwind: {
            path: '$fields'
        }
    },
    {
        $match: {
            'fields.value': {
                $exists: true
            }
        }
    },
    {
        $group: {
            _id: {
                product: '$_id',
                field: '$fields.name'
            },
            value: {
                $last: '$fields.value'
            },
            count: {
                $sum: '$fields.count'
            }
        }
    },
    {
        $project: {
            _id: '$_id.product',
            price: {
                $cond: { if: { $eq: [ '$_id.field', 'price' ] }, then: '$value', else: null }
            },
            sale: {
                $cond: { if: { $eq: [ '$_id.field', 'sale' ] }, then: '$value', else: null }
            },
            count: {
                $cond: { if: { $eq: [ '$_id.field', 'count' ] }, then: '$count', else: 0 }
            }
        }
    },
    {
        $group: {
            _id: '$_id',
            price: {
                $max: '$price'
            },
            sale: {
                $max: '$sale'
            },
            count: {
                $sum: '$count'
            }
        }
    }
])

説明
最初に、フィールド名、フィールド値、およびカウント値を含むフィールドごとの要素を持つ新しい配列を作成します。countフィールドの最後の値を取得するのではなく、累積する必要があるため、フィールドは特別に扱われることに注意してください。したがって、最初の段階のドキュメントは次のようになります。

/* 1 */
{
    "_id" : "2",
    "fields" : [ 
        {
            "name" : "price",
            "value" : 5400,
            "count" : 0.0
        }, 
        {
            "name" : "sale",
            "count" : 0.0
        }, 
        {
            "name" : "count",
            "value" : 0.0,
            "count" : 1
        }
    ]
}

/* 2 */
{
    "_id" : "2",
    "fields" : [ 
        {
            "name" : "price",
            "count" : 0.0
        }, 
        {
            "name" : "sale",
            "value" : 0.2,
            "count" : 0.0
        }, 
        {
            "name" : "count",
            "value" : 0.0,
            "count" : 0
        }
    ]
}

/* 3 */
{
    "_id" : "2",
    "fields" : [ 
        {
            "name" : "price",
            "count" : 0.0
        }, 
        {
            "name" : "sale",
            "count" : 0.0
        }, 
        {
            "name" : "count",
            "value" : 0.0,
            "count" : 1
        }
    ]
}

次に、配列を巻き戻し、フィルタリングして null 値を取り除くため、ステージ 2 および 3 の後、ドキュメントは次のようになります。

/* 1 */
{
    "_id" : "2",
    "fields" : {
        "name" : "price",
        "value" : 5400,
        "count" : 0.0
    }
}

/* 2 */
{
    "_id" : "2",
    "fields" : {
        "name" : "count",
        "value" : 0.0,
        "count" : 1
    }
}

/* 3 */
{
    "_id" : "2",
    "fields" : {
        "name" : "sale",
        "value" : 0.2,
        "count" : 0.0
    }
}

/* 4 */
{
    "_id" : "2",
    "fields" : {
        "name" : "count",
        "value" : 0.0,
        "count" : 0
    }
}

/* 5 */
{
    "_id" : "2",
    "fields" : {
        "name" : "count",
        "value" : 0.0,
        "count" : 1
    }
}

第 4 段階では、フィールドの最後の値と合計countが作成されます。結果は次のようになります。

/* 1 */
{
    "_id" : {
        "product" : "2",
        "field" : "sale"
    },
    "value" : 0.2,
    "count" : 0.0
}

/* 2 */
{
    "_id" : {
        "product" : "2",
        "field" : "count"
    },
    "value" : 0.0,
    "count" : 2
}

/* 3 */
{
    "_id" : {
        "product" : "2",
        "field" : "price"
    },
    "value" : 5400,
    "count" : 0.0
}

値は現在、望ましい結果とは異なる形状の個別のドキュメントにあるため、最終的にグループ化できるものにそれらを投影する必要があります。したがって、第 5 段階以降のドキュメントは次のようになります。

/* 1 */
{
    "_id" : "2",
    "count" : 0.0,
    "price" : null,
    "sale" : 0.2
}

/* 2 */
{
    "_id" : "2",
    "count" : 2,
    "price" : null,
    "sale" : null
}

/* 3 */
{
    "_id" : "2",
    "count" : 0.0,
    "price" : 5400,
    "sale" : null
}

最終段階では、これらのドキュメントを製品ごとに集計します。

于 2016-06-18T13:18:04.303 に答える