Aks
Aks

Reputation: 1234

How to update the increment counter of nested array of objects under array of objects

I have an nested data structure like this:

{
    "_id" : ObjectId("5f51362883fc9424bcc3ed76"),
    "count" : [ 
        {
            "page" : "SHOE",
            "visit_count" : 2,
            "guestip" : [ 
                {
                    "ip" : "192.168.1.4",
                    "visit" : 1
                }, 
                {
                    "ip" : "192.168.1.5",
                    "visit" : 1
                }
            ]
        },
        {
            "page" : "TSHIRTS",
            "visit_count" : 2,
            "guestip" : [ 
                {
                    "ip" : "192.168.1.1",
                    "visit" : 1
                }, 
                {
                    "ip" : "192.168.1.2",
                    "visit" : 1
                }
            ]
        }
    ],
    "createdate" : ISODate("2020-09-03T18:30:00.056Z"),
    "__v" : 0
}

How I can increment the visit counter for 192.168.1.2 ip ib TSHIRTS section.

What I tried: I am using node.js and mongoose;

const isIPExists = (ip, arr) => arr.some(el => String(el.ip) === ip);
//NOTE: Below code is under async function that is why used the await.
const data = await CollectionName.findOne(
 { createdate: { $gte: finaldate } },
 { assetpage_visit_count: { $elemMatch: { page: req.body.page } } },
).exec();
if (data.count.length === 0) {
 //This part works fine
 await CollectionName.updateOne(
  { createdate: { $gte: finaldate } },
  {
    $push: {
      count: {
        page: req.body.page, //Here let's say TSHIRTS is sending
        visit_count: 1,
        guestip: [
          {
            ip: req.body.ip,
            visit: 1
          }
        ]
    },
  },
 ).exec();
} else {
 const storeIpArray = data.count[0].guestip;
let xfilter = {
  $inc: {
    'count.$.visit_count': 1,
  },
  $push: {
    'count.$.guestip': {
      ip: req.body.ip,
      visit: 1
    }
  }
}
 if (isIPExists(req.body.ip, storeIpArray) === true) {
    xfilter = {
      $inc: {
        'count.$.visit_count': 1,
        'count.$.visit_count.$.visit': 1 
      },
    }
  }
  await CollectionName.updateOne(
    {
      createdate: { $gte: finaldate },
      'count.page': req.body.page,
    },
    xfilter,
  ).exec();
}
return res.send("Done")
}

Any help or suggestion is really appreciated for the increment count under nested structure. Pardon for the indenting as code was very long so just split the issue part here and mentioned the code manually.

Upvotes: 0

Views: 255

Answers (1)

Alex Blex
Alex Blex

Reputation: 37038

Use arrayFilters.

This exactly query is very well explain in the documentation Update Nested Arrays in Conjunction with $[] with copy-pasteable examples.

You just had to update field names to match your documents:

db.CollectionName.update(
{}, 
{ $inc: { "count.$[p].guestip.$[ip].visit": 1 } },
{ arrayFilters: [ 
    { "p.page": "TSHIRTS" } , 
    { "ip.ip": "192.168.1.2" } 
] })

Please note, the subdocument with source ip "192.168.1.2" must be in the array for $inc to increment it, so you may need to push it with visit:0 before running the update query.

Upvotes: 1

Related Questions