MongoDB Facet结果格式化

时间:2018-01-09 16:37:27

标签: mongodb mongoose aggregation-framework

我有一个带有$ facet的查询构造,它以这种格式返回结果:

{price_now: [
   { _id: 'apple', price_now: 1.02 },
   { _id: 'melon', price_now: 3.18 },
   { _id: 'cherry', price_now: 2.57 }],
price_15m: [
   { _id: 'apple', price_15m: 1.08 },
   { _id: 'melon', price_15m: 3.12 },
   { _id: 'cherry', price_15m: 2.82 }],
price_30m: [
   { _id: 'apple', price_30m: 1.05 },
   { _id: 'melon', price_30m: 3.04 },
   { _id: 'cherry', price_30m: 2.94 }]

我如何以这种格式获得结果?:

{ _id: 'apple', price_now: 1.02, price_15m: 1.08, price_30m: 1.05 },
{ _id: 'melon', price_now: 3.18, price_15m: 3.12, price_30m: 3.04 },
{ _id: 'cherry', price_now: 2.57, price_15m: 2.82, price_30m: 2.94 }

完整查询如下所示:

var today = new Date();
var shift_15m = new Date(today.getTime()-15*60*1000);
var shift_30m = new Date(today.getTime()-30*60*1000);

food.aggregate( [
    {
        $facet: {
            price_now: [
                {
                    $group: {
                        _id: "$name",
                        price_now: {$last: "$price"}
                    }
                }
            ],
            price_15m: [
                {
                    $match: {
                        date: { "$lte": shift_15m }
                    }
                }, {
                    $group: {
                        _id: "$name",
                        price_5m: {$last: "$price"}
                    }
                }
            ],
            price_30m: [
                {
                    $match: {
                        date: { "$lte": shift_30m }
                    }
                }, {
                    $group: {
                        _id: "$name",
                        price_30m: {$last: "$price"}
                    }
                }
            ]
        }
    }
])

我需要在一次查询中获得不同时间间隔的每种产品的价格。也许你知道一种更好,更快的方法来从不同时间获得价格。 我的MongoDB版本是v3.6.0。我在Node.js App中使用mongoose。

2 个答案:

答案 0 :(得分:0)

根据您的用例可能效率不高,但可以通过facet操作以下列方式合并数组。

确保所有构面类别按名称排序,并且所有阵列中的每一行都包含相同的产品。

然后,您可以先$zip所有方面类别,然后$reduce每个类别合并所有不同的价格,并重复所有产品。

您可以在刻面阶段后添加以下舞台。

{"$project":{
  "data":{
    "$map":{
      "input":{"$zip":{"inputs":["$price_10s","$price_30s", "$price_30m"],"useLongestLength":true}},
      "as":"item",
      "in":{
        "$reduce":{
          "input":"$$item",
          "initialValue":{},
          "in":{"$mergeObjects":["$$this","$$value"]}
        }
      }
    }
  }
}}

答案 1 :(得分:0)

@Veeram,这是完整的构造。

food.aggregate( [
    {
        $facet: {
            price_now: [
                {
                    $group: {
                        _id: "$market_name",
                        price_now: {$last: "$my_time_stamp"}
                    }
                }
            ],
            price_5m: [
                {
                    $match: {
                        my_time_stamp: { "$lte": shift_5m }
                    }
                }, {
                    $group: {
                        _id: "$market_name",
                        price_5m: {$last: "$my_time_stamp"}
                    }
                }
            ],
            price_15m: [
                {
                    $match: {
                        my_time_stamp: { "$lte": shift_15m }
                    }
                }, {
                    $group: {
                        _id: "$market_name",
                        price_15m: {$last: "$my_time_stamp"}
                    }
                }
            ]
        }
    }, {
        "$project":{
            "data":{
                "$map":{
                    "input":{"$zip":{"inputs":["$price_now","$price_5m", "price_15m"],"useLongestLength":true}},
                    "as":"item",
                    "in":{
                        "$reduce":{
                            "input":"$$item",
                            "initialValue":{},
                            "in":{"$mergeObjects":["$$this","$$value"]}
                        }
                    }
                }
            }
        }
    }
], function (err, result) {
    if (err) {
         console.log(err);
    } else {
        console.log(result)
    };
});