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
Hi @harry_potter3,
After reviewing your question, I would say updating this nested field is anti-pattern. Typically, top-level fields with dot notation can be handled; however, for this case, it both a nested field and using dot notation, so it may not be possible.
Here’s more information on the limitations of using dot or dollar notation in the field name.
Do you mind sharing the compatibility issue?
aneroid
(Anirudh Dutt)
3
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.
aneroid
(Anirudh Dutt)
4
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
1 Like