繁体   English   中英

MongoDB 使用查找聚合过滤掉子文档

[英]MongoDB filtering out subdocuments with lookup aggregation

我们的项目数据库有一个名为 values 的上限集合,每隔几分钟就会更新一次来自传感器的新数据。 这些传感器都属于单个传感器节点,我想在单个聚合中查询这些节点的最后数据。 我遇到的问题是只过滤掉所有类型的传感器中的最后一个,同时仍然只有一个(有效的)查询。 我环顾四周,找到了 $group 参数,但我似乎无法弄清楚在这种情况下如何正确使用它。

数据库的结构如下:

节点:

{
    "_id": 681
    "sensors": [
            {
                "type": "foo"
            },
            {
                "type": "bar"
            }
    ]
}

价值观:

{
    "_id" : ObjectId("570cc8b6ac55850d5740784e"),
    "timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
    "type" : "foo",
    "nodeid" : 681,
    "value" : 10
}

{
    "_id" : ObjectId("190ac8b6ac55850d5740776e"),
    "timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
    "type" : "bar",
    "nodeid" : 681,
    "value" : 20
}

{
    "_id" : ObjectId("167bc997bb66750d5740665e"),
    "timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
    "type" : "bar",
    "nodeid" : 200,
    "value" : 20
}

{
    "_id" : ObjectId("110cc9c6ac55850d5740784e"),
    "timestamp" : ISODate("2016-04-09T12:06:46.344Z"),
    "type" : "foo",
    "nodeid" : 681,
    "value" : 12
}

所以让我们想象一下我想要来自节点 681 的数据,我想要一个这样的结构:

节点:

{
    "_id": 681
    "sensors": [
            {
                "_id" : ObjectId("570cc8b6ac55850d5740784e"),
                "timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
                "type" : "foo",
                "nodeid" : 681,
                "value" : 10
            },
            {
                "_id" : ObjectId("190ac8b6ac55850d5740776e"),
                "timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
                "type" : "bar",
                "nodeid" : 681,
                "value" : 20
            }
    ]
}

请注意 foo 的一个值是如何不被查询的,因为我只想在有多个值的情况下获取可能的最新值(情况总是如此)。 集合的排序已经根据时间戳,因为集合是有上限的。

我有这个查询,但它只是从数据库中获取所有值(这在一生中太多了,更不用说网络应用程序的一个请求了),所以我想知道如何在聚合之前对其进行过滤.

询问:

db.nodes.aggregate(
        [
            {
                $unwind: "$sensors"
            }, 
            {
                $match:{
                    nodeid: 681
                       }
            }, 
            {
                $lookup:{
                        from: "values", localField: "sensors.type", foreignField: "type", as: "sensors"
                    }
             }
         }
    ]
)

尝试这个

  // Pipeline
  [
    // Stage 1 - sort the data collection if not already done (optional)
    {
      $sort: {
       "timestamp":1
      }
    },

    // Stage 2 - group by type & nodeid then get first item found in each group
    {
      $group: {
        "_id":{type:"$type",nodeid:"$nodeid"},
        "sensors": {"$first":"$$CURRENT"}  //consider using $last if your collection is on reverse
      }
    },

    // Stage 3 - project the fields in desired
    {
      $project: {
       "_id":"$sensors._id",
       "timestamp":"$sensors.timestamp",
       "type":"$sensors.type",
       "nodeid":"$sensors.nodeid",
       "value":"$sensors.value"
      }

    },

    // Stage 4 - group and push it to array sensors
    {
      $group: {
        "_id":{nodeid:"$nodeid"},
        "sensors": {"$addToSet":"$$CURRENT"}
      }
    }

  ]

就我获得的文档结构而言,没有必要使用 $lookup,因为所有数据都在读数(值)集合中。

请参阅建议的解决方案:

db.readings.aggregate([{
            $match : {
                nodeid : 681
            }
        },
        {
            $group : {
                _id : {
                    type : "$type",
                    nodeid : "$nodeid"
                },
                readings : {
                    $push : {
                        timestamp : "$timestamp",
                        value : "$value",
                        id : "$_id"
                    }
                }
            }
        }, {
            $project : {
                _id : "$_id",
                readings : {
                    $slice : ["$readings", -1]
                }
            }
        }, {
            $unwind : "$readings"
        }, {
            $project : {
                _id : "$readings.id",
                type : "$_id.type",
                nodeid : "$_id.nodeid",
                timestamp : "$readings.timestamp",
                value : "$readings.value",

            }
        }, {
            $group : {
                _id : "$nodeid",
                sensors : {
                    $push : {
                        _id : "$_id",
                        timestamp : "$timestamp",
                        value : "$value",
                        type:"$type"
                    }
                }
            }
        }

    ])

和输出:

{
    "_id" : 681,
    "sensors" : [ 
        {
            "_id" : ObjectId("110cc9c6ac55850d5740784e"),
            "timestamp" : ISODate("2016-04-09T12:06:46.344Z"),
            "value" : 12,
            "type" : "foo"
        }, 
        {
            "_id" : ObjectId("190ac8b6ac55850d5740776e"),
            "timestamp" : ISODate("2016-04-12T12:06:46.344Z"),
            "value" : 20,
            "type" : "bar"
        }
    ]
}

欢迎任何意见!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM