简体   繁体   English

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

[英]MongoDB filtering out subdocuments with lookup aggregation

Our project database has a capped collection called values which gets updated every few minutes with new data from sensors.我们的项目数据库有一个名为 values 的上限集合,每隔几分钟就会更新一次来自传感器的新数据。 These sensors all belong to a single sensor node, and I would like to query the last data from these nodes in a single aggregation.这些传感器都属于单个传感器节点,我想在单个聚合中查询这些节点的最后数据。 The problem I am having is filtering out just the last of ALL the types of sensors while still having only one (efficient) query.我遇到的问题是只过滤掉所有类型的传感器中的最后一个,同时仍然只有一个(有效的)查询。 I looked around and found the $group argument, but I can't seem to figure out how to use it correctly in this case.我环顾四周,找到了 $group 参数,但我似乎无法弄清楚在这种情况下如何正确使用它。

The database is structured as follows:数据库的结构如下:

nodes:节点:

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

values:价值观:

{
    "_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
}

so let's imagine I want the data from node 681, I would want a structure like this:所以让我们想象一下我想要来自节点 681 的数据,我想要一个这样的结构:

nodes:节点:

{
    "_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
            }
    ]
}

Notice how one value of foo is not queried, because I want to only get the latest value possible if there are more than one value (which is always going to be the case).请注意 foo 的一个值是如何不被查询的,因为我只想在有多个值的情况下获取可能的最新值(情况总是如此)。 The ordering of the collection is already according to the timestamp because the collection is capped.集合的排序已经根据时间戳,因为集合是有上限的。

I have this query, but it just gets all the values from the database (which is waaay too much to do in a lifetime, let alone one request of the web app), so I was wondering how I would filter it before it gets aggregated.我有这个查询,但它只是从数据库中获取所有值(这在一生中太多了,更不用说网络应用程序的一个请求了),所以我想知道如何在聚合之前对其进行过滤.

query:询问:

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

Try this尝试这个

  // 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"}
      }
    }

  ]

as far as I got document structure, there is no need to use $lookup as all data is in readings(values) collection.就我获得的文档结构而言,没有必要使用 $lookup,因为所有数据都在读数(值)集合中。

Please see proposed solution:请参阅建议的解决方案:

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"
                    }
                }
            }
        }

    ])

and output:和输出:

{
    "_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"
        }
    ]
}

Any comments welcome!欢迎任何意见!

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

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