0

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.

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

thanks for your support. Can you through some lights on the term "ubdocument with source ip "192.168.1.2" must be in the array for $inc to increment it". As I run the query on mongo console and get the error i.e "The path 'count.1.guestip' must exist in the document in order to apply array updates."
It is hard to believe that this exact query produces this error. The way arrayFilters works is it applies $inc to all matching subdocuments or does not apply at all. If I reword the last sentence: the update will not add new element to guestip array even if page filter matches. The error you have suggests you are trying to do an upsert. If so, it's not gonna work.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.