MongoDB匹配并切片多个子数组

时间:2016-04-19 08:52:41

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

我目前有这个架构

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 }
});

我尝试构建的查询应该通过" hid"来搜索架构,然后只选择"传感器","执行器"和"状态"对与我提供的nid匹配的对象进行数组排列,然后将结果限制为每个数组的10个元素。

2 个答案:

答案 0 :(得分:1)

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

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个元素

答案 1 :(得分: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",因为{ "$sum": { "$sum": "$array" } } 始终

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

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

最后:

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

但还有一个:

  • 所有“数组”操作,例如$filter$slice$sum甚至“集合运算符”都应始终与每个“内联”使用另外,在那些操纵相同阵列内容的情况下。现在甚至适用于使用$max$group进行包装,因为它们可以直接在数组本身上工作,并且通常看起来很奇怪但有效:

     using (var db = new FORMS())
                    {
                        //Get Chapters from selected form
                        var query = from b in db.CHAPTERS
                                    select b;
    
                        //Create treeview hierarchy
                        foreach (var rootItem in query)
                        {
                            TreeNode myNode = new TreeNode(rootItem.titulo, rootItem.id.ToString());
    
                            var childQuery = from b in db.SECTIONS
                                             where b.idChapter = rootItem.id
                                             select b;
                            //Add childs
                            foreach (var childItem in childQuery)
                            {
                                TreeNode myChildNode = new TreeNode(childItem.titulo, childItem.id.ToString());
                                myNode.ChildNodes.Add(myChildNode);
                            }
    
                            ChapterTreeView.Nodes.Add(myNode);
                        }
                    }
    
    在{{3}}阶段内的

    结构。