解決策
次のパイプラインにより、目的の結果が得られるはずです
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
}
最終段階では、これらのドキュメントを製品ごとに集計します。