2016-06-18 5 views
0

'account'コレクションには文書があります。一部のフィールドは宣言できません。これを見てください。

{ _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なり、このクエリを使用します。 $groupの前に$projectを使用する必要があります。現在のフィールドがnullの場合、最後のドキュメントの値を保持するにはどうすればよいですか?

+0

これは、選択した言語にデータを読み込む必要があると思います。任意のデータフレームライブラリ(Pythonの 'pandas'など)はこれを扱います。 –

答えて

0

現在のソリューションは3つのクエリで動作します。

1. - Group by `product` and sum `count` field 
    - Remove any entries, where `count` is 0 and lower 
    - Hold `_ids` array as `product_ids` 
    - Hold result array as `firstArray` 

2. - Match any entries, where 
      - `sale` is 0 and greater 
      - `_id` is in `product_ids` 
    - Group by `product` and get last `sale` field 
    - Hold result array as `secondArray` 

3. - Match any entries, where 
      - `price` is 0 and greater 
      - `_id` is in `product_ids` 
    - Group by `product` and get last `price` field 
    - Enumerate `firstArray` and add `count` field to entries 
    - Enumerate `secondArray` and add `sale` field to entries 

とコード

let firstArray 
let secondArray 
let product_ids 
Promise.resolve().then(function() { 
    return db.collection(ACCOUNT).aggregate([ 
     { 
      $group: { 
       _id: '$product', 
       count: { $sum: '$count' } 
      } 
     }, { 
      $match: { 
       count: { $gt: 0 } 
      } 
     } 
    ], { allowDiskUse: true }).toArray() 
}).then(function (array) { 
    firstArray = array 
    product_ids = array.map(function (item) { 
     return item._id 
    }) 
    return db.collection(ACCOUNT).aggregate([ 
     { 
      $match: { 
       product: { $in: product_ids }, 
       sale: { $gte: 0 } 
      } 
     }, { 
      $group: { 
       _id: '$product', 
       sale: { $last: '$sale' } 
      } 
     } 
    ], { allowDiskUse: true }).toArray() 
}).then(function (array) { 
    secondArray = array 

    return db.collection(ACCOUNT).aggregate([ 
     { 
      $match: { 
       product: { $in: product_ids }, 
       price: { $gte: 0 } 
      } 
     }, { 
      $group: { 
       _id: '$product', 
       price: { $last: '$price' } 
      } 
     } 
    ], { allowDiskUse: true }).toArray() 
}).then(function (array) { 
    req.data = array.map(function (item) { 
     let count = 0 
     let sale = 0 
     firstArray.some(function (_item) { 
      if (item._id.toHexString() == _item._id.toHexString()) { 
       count = _item.count 
       return true 
      } 

      return false 
     }) 
     secondArray.some(function (_item) { 
      if (item._id.toHexString() == _item._id.toHexString()) { 
       sale = _item.sale 
       return 
      } 
      return false 
     }) 

     item.count = count 
     item.sale = sale 
     return item 
    }) 
    next() 
}) 
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 
} 

最後の段階では、製品ごとにこれらの文書を集計するだけです。

+1

素晴らしい! +1の仕事と詳細な説明! – tengobash