【问题标题】:MongoDB Match and Slice multiple child arraysMongoDB 匹配和切片多个子数组
【发布时间】:2016-08-11 08:00:42
【问题描述】:

我目前有这个架构

var dataSchema = new Schema({
hid: { type: String },
sensors: [{
    nid: { type: String },
    sid: { type: String },
    data: {
        param1: { type: String },
        param2: { type: String },
        data: { type: String }
    },
    date: { type: Date, default: Date.now }
}],
actuators: [{
    nid: { type: String },
    aid: { type: String },
    control_id: { type: String },
    data: {
        param1: { type: String },
        param2: { type: String },
        data: { type: String }
    },
    date: { type: Date, default: Date.now }
}],
status: [{
    nid: {type: String},
    status_code: {type: String},
    date: { type: Date, default: Date.now }
}],
updated: { type: Date, default: Date.now },
created: { type: Date }
});

我正在尝试构建的查询应该通过“隐藏”搜索架构,然后只从“传感器”、“执行器”和“状态”数组中选择与我提供的 nid 匹配的对象和然后还将每个数组的结果限制为 10 个元素。

【问题讨论】:

    标签: javascript mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    实际上,当“一个”可以使用时,不要使用多个管道阶段。您包含的每个管道阶段都有效地增加了处理“时间”,因为它是另一个数据传递。

    所以逻辑上在“单一”阶段有效的东西,应该停留在“单一”阶段:

    Data.aggregate([
        { "$match": { "hid": hid } },
        { "$project": {
            "sensors": {
                "$slice": [
                    { "$filter": { 
                        "input": "$sensors", 
                        "as": "sensor", 
                        "cond": { "$eq": [ "$$sensor.nid", nid ] } 
                    }},
                    -10
                ]
            },
            "actuators": {
                "$slice": [
                    { "$filter": { 
                        "input": "$actuators", 
                        "as": "actuator", 
                        "cond": { "$eq": [ "$$actuator.nid", nid ] } 
                    }},
                    -10
                ]
            },
            "status": {
                "$slice": [
                    { "$filter": { 
                        "input": "$status", 
                        "as": "status", 
                        "cond": { "$eq": [ "$$status.nid", nid ] } 
                    }},
                    -10
                ]
            },
            "updated": 1,
            "created": 1
        }}
    ])
    

    此外,没有必要在包含中使用"_id": 1,因为"_id"总是包含在内,除非明确“排除”。

    主要情况是尽量不要创建不必要的阶段,因为这对性能不利。这方面的良好指标是:

    • $project 后跟 $project,通常意味着您可以在一个阶段完成此操作。
    • 无论如何,$project 后跟 $group 可能会被“优化器”压缩,但你“应该”养成将两者结合起来的习惯。
    • $project 后跟 $match,应该表明您可能应该在单个阶段中使用 $redact。由于您可能使用 $project 来根据计算生成字段,因此在 $match 中考虑了这些字段。

    最后:

    • $unwind$match 之前,真的应该是$filter$project“之前”$unwind。因为实际上它在文档中“过滤”的速度要快得多,并且由于已过滤内容的输出较少,还可以节省处理 $unwind 的成本。

    还有一个:

    • 所有“数组”操作,如$map$filter$slice,甚至“集合运算符”都应该始终“串联”使用,以防它们在操作相同的数组内容。现在同样适用于使用 $sum$max 进行包装,因为它们可以直接在数组本身上工作,而且通常看起来很奇怪但很有效:

      { "$sum": { "$sum": "$array" } }
      

      $group 阶段内的结构。

    【讨论】:

    • 非常感谢您的解释和建议
    【解决方案2】:

    这可以通过聚合框架来实现。 查询如下所示:

    Data.aggregate([
                { "$match": { "hid": hid } },
                { "$project": {
                    "_id": 1,
                    "sensors": {
                        "$filter": { "input": "$sensors", "as": "sensor", "cond": { "$eq": [ "$$sensor.nid", nid ] } }
                    },
                    "actuators": {
                        "$filter": { "input": "$actuators", "as": "actuator", "cond": { "$eq": [ "$$actuator.nid", nid ] } }
                    },
                    "status": {
                        "$filter": { "input": "$status", "as": "state", "cond": { "$eq": [ "$$state.nid", nid ] } }
                    },
                    "updated": 1,
                    "created": 1
                }},
                { "$project": {
                    "_id": 1,
                    "sensors": {
                        "$slice": [ "$sensors", -10 ]
                    },
                    "actuators": {
                        "$slice": [ "$actuators", -10 ]
                    },
                    "status": {
                        "$slice": [ "$status", -10 ]
                    },
                    "updated": 1,
                    "created": 1
                }}
            ]).exec(function(err,data) {
            });
    

    它使用$match 查找架构,$filter 从数组中仅挑选与提供的nid 匹配的元素,然后使用$slice 从过滤后的数组中挑选最后 10 个元素

    【讨论】:

    • 很好,您在这里得出了自己的结论,但是您应该注意这里存在一些结构性问题,这些问题对性能有很大影响。
    • 非常感谢您的解释和建议:)
    猜你喜欢
    • 2018-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    相关资源
    最近更新 更多