2 / 4
Jun 2024

help me with this problem:

I using pymongo to update my mongoDB database using this code:

updates = {"$inc":{}} user_ip = "127.0.0.1"  updates["$inc"][f"ips.{user_ip}"] = 1

creates something like this in the mongoDB document:

"ips": { "127": { "0": { "0": { "1": 1 } } } }

but I want it to be like:

"ips": { "127.0.0.1": 1 }

I cannot replace the . of the ip-address to any other characters in the DB because of some compatibility issues.

but if I do this it works fine:

url_data["ips"][user_ip] = url_data["ips"].get(user_ip, 0) + 1 updates["$set"]["ips"] = url_data["ips"]

url_data is the full document and querying it and updating it whole is not efficient for me

9 months later

Assuming you’re on MongoDB 5 or above, to avoid issues with the dots in the IP address being treated as a path expression, you will need to use $getField and $setField.

Put that in an update aggregation pipeline to first get the current value, add 1, then set that as the value. In Python, you could do:

user_ip = "127.0.0.1" update_pipeline = [ { "$set": { "ips": { "$setField": { "field": user_ip, "input": "$ips", "value": { "$add": [ { "$getField": { "field": user_ip, "input": "$ips", } }, 1 ] } } } } } ] collection.update_many({ <user filter here> }, update_pipeline)

Mongo Playground example with more docs. Note that non-matching IP addresses are un-changed.

The real anti-pattern here is the usage of the IP address as the key. Instead having the IP addresses as the keys like this:

ips: { "127.0.0.1": 100, "192.168.0.1": 50 }

You should be using known keys/names as the field and value. That is the Attribute Pattern:

ips: [ {addr: "127.0.0.1", count: 100}, {addr: "192.168.0.1", count: 50}, ]

Then you could use a standard operation to Update Documents in an Array:

db.collection.update({ _id: 1, // userID "ips.addr": "127.0.0.1" // IP address }, { $inc: { "ips.$.count": 1 } })

Mongo Playground update query with Attribute Pattern