MongoDB how find a certainly named array

Viewed 36

Okay, the title is a bit un-detailed (you could only fit so much in there) but I will explain, so imagine this structure;

{"_id": 123}

Easy right? So what I am doing is adding a field when it does not detect a duplicate, for example if id 123 got the fruit; apple with an amount counter and displaying if it is healthy, then apple will be added into the field, simple, but I'm not done, here it is so far;

{"_id": 123, "Apple": {"Healthy?": "Yes", "amount": 1}}

Now let's say id 123 decides to get him/her a pizza, then the field will once again update;

{"_id": 123, "Apple": {"Healthy?": "Yes", "amount": 1}, "Pizza": {"Healthy?": No, "amount": 1}}

So far, very straightforward, but what if id 123 gets himself another apple? Well also very simple I just used; collection.update({"_id": 123},{"$inc": {"Apple.amount": 1}}) this now turns into;

{"_id": 123, "Apple": {"Healthy?": "Yes", "amount": 2}, "Pizza": {"Healthy?": No, "amount": 1}}

Now if we try to implement both of these together; i.e; detecting if a similar field has been inserted, then update the value, or detect that no fields exist under this id, insert the new data. Right now I have;

try:
  collection.update({"_id": user},{"$inc": {f"{thing}.amount": 1}})  
except:
  collection.update_one({"_id" : user},{"$set":{f"{thing}": idf}})

People who don't know python or doesn't understand this be like; whoa whoa whoa this was a cakewalk until this showed up. Allow me to explain, what is happening is I am getting the user id as {user}, so if user 123 were to use this, then it would be {"_id": "123"} but I have that taken care of, {thing} is the object obtained, if user 123 gets an apple then {thing} would be Apple. In the second update, there is {idf} this is basically how I get the data for each object, having a json store this and pulling the object data and inserting this. Now what this code does right now is it just inserts {"_id": 123, "Apple": {"amount": 1}} if you didn't know, using $inc will create a new field if it does not detect a current field, so it will try to update it, since it succeeds nothing else will happen. What I want this to do is to update the object amount, if it does not manage to detect a file similar to the format, then insert a fresh field with my data on the json. What I have done is try and find the object under the id and then according to that update adaptively, but I have tried so many ways to get this to work, what I thought would work the most is find = collection.find({"_id": user, f"{thing}": {}} ), but it just doesn't work, it doesn't even bother to find anything because there is an error.

Can anyone take a stab at this?

1 Answers

You can use update with aggregation pipeline starting from MongoDB 4.2,

Assume you have the below input data:

user = 123
thing = "Apple"
idf = {
  "Healthy?": "Yes",
  "amount": 1
}

The query would be,

  • $cond to check if thing is not missing type
    • it's not missing then increment amount by $add and merge default properties with an incremented amount using $mergeObjects
    • if it's missing then add thing new properties
collection.update(
  { '_id': user },
  [{
    '$set': {
      f"{thing}": {
        '$cond': [
          { '$ne': [{ '$type': f"${thing}" }, "missing"] },
          {
            '$mergeObjects': [
              f"${thing}",
              { 'amount': { '$add': [f"${thing}.amount", 1] } }
            ]
          },
          idf
        ]
      }
    }
  }]
)

Playground

Related