首页 > 解决方案 > 使用 mongoDB 按平均值查找值组

问题描述

我有以下数据:

    { 
        "_id" : ObjectId("5e11d9e9c96b354478d9f1b2"), 
        "type" : ObjectId("5c57150e4433c100152eed27"), 
        "ppc" : 100, 
        "cycleString" : "Jan 20", 
        "created_at" : ISODate("2020-01-05T12:43:21.943+0000"), 
    }
    { 
        "_id" : ObjectId("5e11dc08c96b354478d9f1d4"), 
        "type" : ObjectId("5c57150e4433c100152eed27"), 
        "ppc" : 104, 
        "cycleString" : "Jan 20", 
        "created_at" : ISODate("2020-01-05T12:52:24.985+0000"), 
    }
    { 
        "_id" : ObjectId("5e11dc40c96b354478d9f1e7"), 
        "type" : ObjectId("5c57150e4433c100152eed27"), 
        "ppc" : 125, 
        "cycleString" : "Jan 20", 
        "created_at" : ISODate("2020-01-05T12:53:20.967+0000"), 
    }
    { 
        "_id" : ObjectId("5e11dcdec96b354478d9f206"), 
        "type" : ObjectId("5c57150e4433c100152eed27"), 
        "ppc" : 126.1, 
        "cycleString" : "Jan 20",
        "created_at" : ISODate("2020-01-05T12:55:20.967+0000"), 
   }

和一个常数 RANGE_PERCENT(允许范围与平均值的百分比,对于此示例,假设为 2%)。

我需要得到一个列表,其中这些数据按平均价格分组。棘手的部分是平均值的变化取决于所选组

例如:对于以下价格 [100, 104, 125, 126.1](按 created_at 排序)我应该得到 2 组:

    Group A:  
    [100, 104]    
    99.96 < 102 < 104.04 (avgMin < averagePrice < avgMax)  
    Group B:  
    [125, 126.1]  
    123.039 < 125.55 < 128.061 (avgMin < averagePrice < avgMax)
  1. 我应该首先计算每个可能组的最小值和最大值
  2. 计算可能的组平均值
  3. 然后得到允许的最小值和最大值平均值

    avgMin = avg - (avg * RANGE_PERCENT / 100)
    avgMax = avg + (avg * RANGE_PERCENT / 100)

  4. 所有适合该范围的价格(avgMin < price < avgMax)都应该在该组中。

    • 如果和对象可以适合两个组,那么它应该由组长度决定。

这是我到目前为止所拥有的:

首先,我使用与下面相同的查询检查整个组的验证。如果该组有效,那么我继续下一组。如果它无效,那么我使用以下 JS 代码为“内部组”创建所有可能的组合:

    function getCombinations(boxes) {
        let result = [];
        let comb = function (prefix, boxes) {
            for (let i = 0; i < boxes.length; i++) {
                const boxObjId = utils.toMongooseObjectId(boxes[i]._id);
                result.push([...prefix, boxObjId]);
                comb([...prefix, boxObjId], boxes.slice(i + 1));
            }
        }
        comb([], boxes);
        return result;
    }

在我拥有所有可能的组合后,我按组长度对它们进行排序并开始逐个查询,直到找到第一个有效组。

我不那么有效的查询:

db.getCollection("boxes").aggregate(
    [
        { 
            "$match" : {
                "type" : ObjectId("5c57150e4433c100152eed27"), 
                "cycleString" : ["Jan 19", "Jan 20"]
            }
        }, 
        { 
            "$group" : {
                "_id" : {
                    "cycleString" : "$cycleString", 
                    "priceTier" : "$priceTier", 
                    "type" : "$type", 
                    "sealed" : "$sealed"
                }, 
                "averagePpc" : {
                    "$avg" : "$ppc"
                }, 
                "minPpc" : {
                    "$min" : "$ppc"
                }, 
                "maxPpc" : {
                    "$max" : "$ppc"
                }, 
                "boxes" : {
                    "$push" : "$$ROOT"
                }
            }
        }, 
        { 
            "$project" : {
                "averagePpc": 1.0,
                "minPpc": 1.0,
                "maxPpc": 1.0,
                "lowestAsk": 1.0,
                "diff" : {
                    "$subtract" : [
                        "$maxPpc", 
                        "$minPpc"
                    ]
                }, 
                "averagePercent" : {
                    "$multiply" : [
                        "$averagePpc", 
                        2.0, 
                        0.01
                    ]
                }
            }
        }, 
        { 
            "$project" : {
                "averagePpc": 1.0,
                "minPpc": 1.0,
                "maxPpc": 1.0,
                "lowestAsk": 1.0,
                "diff": 1.0,
                "averagePercent": 1.0,
                "allowedHigh" : {
                    "$add" : [
                        "$averagePpc", 
                        "$averagePercent"
                    ]
                }, 
                "allowedLow" : {
                    "$subtract" : [
                        "$averagePpc", 
                        "$averagePercent"
                    ]
                },
                "boxes": 1.0
            }
        }, 
        { 
            "$project" : {
                "averagePpc": 1.0,
                "minPpc": 1.0,
                "maxPpc": 1.0,
                "lowestAsk": 1.0,
                "diff": 1.0,
                "averagePercent": 1.0,
                "allowedHigh": 1.0,
                "allowedLow": 1.0,
                "validated" : {
                    "$cond" : {
                        "if" : {
                            "$gte" : [
                                "$maxPpc", 
                                "$allowedHigh"
                            ]
                        }, 
                        "then" : false, 
                        "else" : {
                            "$cond" : {
                                "if" : {
                                    "$lt" : [
                                        "$minPpc", 
                                        "$allowedLow"
                                    ]
                                }, 
                                "then" : false, 
                                "else" : true
                            }
                        }
                    }
                }, 
                "boxes" : 1.0
            }
        }
    ]
);

所以我的问题是,我能以某种方式提高效率吗?也许不是多次调用它以使其成为一个还将包含 JS getCombinations() 函数的查询?

标签: mongodbaggregation-framework

解决方案


推荐阅读