mongodb implements an array object summing method instance

  • 2020-11-26 19:03:29
  • OfStack

preface

When mongodb calculates an array of collections, it's common to think of using $group and $sum, but what if you have multiple json objects in the array, and you need to filter the contents of multiple objects according to the criteria?

Now let's implement it by assuming that there is an user collection in mongodb, whose data is as follows:


/* 1 */
{
 "_id" : ObjectId("5c414a6a0847e00385143003"),
 "date" : "2019-01-18 09",
 "data" : [ 
 {
  "app_platform" : "ios",
  "user" : 3028
 }, 
 {
  "app_platform" : "android",
  "user" : 4472
 }, 
 ]
}
...

Now we need to count the total number of user of date date "2019-01-1809" and app_platform type "ios"

If so, consider how the mongodb statement might be implemented.

There is an implementation that is very important in the implementation process, namely $unwind, official explanation:

[

Deconstructs an array field from the input documents to output a document for each element. Each output document is the input document with the value of the array field replaced by the element.

Deconstruct 1 array field from the input document, and output 1 document for each element. Each output document is an input document, and the values of the array fields are replaced by elements.

]

Therefore, we thought of splitting the data array object into strips to simplify the complexity. The mongodb statement is as follows:


db.getCollection('user').aggregate([
 {
 $project: { _id: 1, data: 1, date: 1}
 },
 { 
 $match: {"date": "2019-01-18 09"}
 }, 
 {
 $unwind: "$data"
 },
])

The results are as follows:

[

/* 1 */
{
"_id" : ObjectId("5c414a6a0847e00385143003"),
"date" : "2019-01-18 09",
"data" : {
"app_platform" : "ios",
"user" : 3028
}
}
/* 2 */
{
"_id" : ObjectId("5c414a6a0847e00385143003"),
"date" : "2019-01-18 09",
"data" : {
"app_platform" : "android",
"user" : 4472
}
}

]

You can see that the data is changed from an array to multiple document data, so the problem is changed to the total number of calculated user. Do you think the problem becomes easier? Moreover, we can continue to use $match to filter the app_platform data, and the mongodb statement is as follows:


db.getCollection('user').aggregate([
 {
 $project: { _id: 1, data: 1, date: 1}
 },
 { 
 $match: {"date": "2019-01-18 09"}
 }, 
 {
 $unwind: "$data"
 },
 {
 $match: {
 "data.app_platform": { $in: ["ios"]}
 },
 }
])

The execution results are as follows:

[

/* 1 */
{
"_id" : ObjectId("5c414a6a0847e00385143003"),
"date" : "2019-01-18 09",
"data" : {
"app_platform" : "ios",
"user" : 3028
}
}

]

You can see that the data has been filtered, and if you look confidently at the effect of the two $match, you can see that mongodb is executed sequentially, that is, $match ACTS on the set of results that preceded it

Let's go ahead and use group ​ sum can sum the user field in data. The mongodb statement is as follows:


db.getCollection('user').aggregate([
 {
 $project: { _id: 1, data: 1, date: 1}
 },
 { 
 $match: {"date": "2019-01-18 09"}
 }, 
 {
 $unwind: "$data"
 },
 {
 $match: {
 "data.app_platform": { $in: ["ios"]}
 }
 },
 {
 $group: { _id: null, "user": {$sum: "$data.user"}}
 }
])

The results are as follows:

[

/* 1 */
{
"_id" : null,
"user" : 7500
}

]

The calculated user is the data we need.

In fact, the difficulties are as follows:

The $unwind instruction makes the problem much easier by converting the array object data to multiple simple data formats when calculating it The execution order of mongodb, $project, $match are executed sequentially and used for the results of previous operations

Understanding these two points, I believe that no matter how difficult mongodb statement you can achieve.

happy coding!

conclusion


Related articles: