0

Whenever I updated my insert_one with a new field to use, I had to always delete the old posts in the collection. I know there are manual methods of updating such fields using update_many but I know it's inefficient.

For example:

posts.insert_one({
    "id": random.randint(1,10000)
    "value1": "value1",
    "value2": "value2"
})

I use the following code to check if the document exists or not. How would this work for a field?

if posts.find({'id': 12312}).count() > 0:

I know I can easily overwrite the previous data but I know people won't enjoy having their data wiped every other month.

Is there a way to add the field to a document in Python?

3 Answers 3

1

How would this work for a field?

You can use $exists to check whether a field exists in a doc.

In your case, you can combine this with find

find({ 'id':1, "fieldToCheck":{$exists:"true"}})

It will return the doc if it exists with id = 1, fieldToCheck is present in doc with id = 1

You can skip id=1, in that case, it will return all docs where fieldToCheck exists

Is there a way to add the field to a document in Python?

You could use update with new field, it will update if it is present else it will insert.

update({"_id":1}, {field:"x"})

If field is present, it will set to x else it will add with field:x

Beware of update options like multi, upsert

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

Comments

1

Yes you can you use update command in mongoDB shell to do that. check here

This is the command to use...

db.collection.update({},{$set : {"newfield":1}},false,true)

The above will work in the mongoDB shell. It will add newfield in all the documents, if it is not present.

If you want to use Python, use pymongo.

For python, following command should work

db.collection.update({},{"$set" : {"newfield":1}},False, True)

Comments

0

Thanks to john's answer I have made an entire solution that automatically updates documents without the need to run a task meaning you don't update inactive documents.

import datetime
import pymongo

database = pymongo.MongoClient("mongodb://localhost:27017")  # Mongodb connection
db = database.maindb  # Database
posts = db.items  # Collection within a database


# A schema equivalent function that returns the object
def user_details(name, dob):
    return {
        "username": name,  # a username/id
        "dob": dob,  # some data
        "level": 0,  # some other data
        "latest_update": datetime.datetime.fromtimestamp(1615640176)
        # Must be kept to ensure you aren't doing it that often
    }


# The first schema changed for example after adding a new feature
def user_details2(name, dob, cake):
    return {
        "username": name,  # a username/id
        "dob": dob,  # Some data
        "level": 0,  # Some other data
        "cake": cake,  # Some new data that isn't in the document
        "latest_update": datetime.datetime.utcnow()  # Must be kept to ensure you aren't doing it that often
    }


def check_if_update(find, main_document,
                    collection):  # parameters: What you find a document with, the schema dictionary, then the mongodb collection
    if collection.count_documents(find) > 0:  # How many documents match, only proceed if it exists

        fields = {}  # Init a dictionary

        for x in collection.find(find):  # You only want one for this to work
            fields = x

        if "latest_update" in fields:  # Just in case it doesn't exist yet
            last_time = fields["latest_update"]  # Get the time that it was last updated
            time_diff = datetime.datetime.utcnow() - last_time  # Get the time difference between the utc time now and the time it was last updated
            if time_diff.total_seconds() < 3600:  # If the total seconds of the difference is smaller than an hour
                print("return")
                return

        db_schema = main_document  # Better naming
        db_schema["_id"] = 0  # Adds the _id schema_key into the dictionary

        if db_schema.keys() != fields:
            print("in")

            for schema_key, schema_value in db_schema.items():

                if schema_key not in fields.keys():  # Main key for example if cake is added and doesn't exist in db fetched fields
                    collection.update_one(find, {"$set": {schema_key: schema_value}})

                else:  # Everything exists and you want to check for if a dictionary within that dictionary is changed
                    try:
                        sub_dict = dict(schema_value)  # Make the value of it a dictionary

                        # It exists in the schema dictionary but not in the db fetched document
                        for key2, value2 in sub_dict.items():
                            if key2 not in fields[schema_key].keys():
                                new_value = schema_value
                                new_value[
                                    key2] = value2  # Adding the key and value from the schema dictionary that was added
                                collection.update_one(find,
                                                      {"$set": {schema_key: new_value}})

                        # It exists in the db fetched document but not in the schema dictionary
                        for key2, value2 in fields[schema_key].items():
                            if key2 not in sub_dict.keys():

                                new_dict = {}  # Get all values, filter then so that only the schema existent ones are passed back
                                for item in sub_dict:
                                    if item != key2:
                                        new_dict[item] = sub_dict.get(item)
                                collection.update_one(find, {"$set": {schema_key: new_dict}})

                    except:  # Wasn't a dict
                        pass

            # You removed a value from the schema dictionary and want to update it in the db
            for key2, value2 in fields.items():
                if key2 not in db_schema:
                    collection.update_one(find, {"$unset": {key2: 1}})
    else:
        collection.insert_one(main_document)  # Insert it because it doesn't exist yet


print("start")
print(posts.find_one({"username": "john"}))

check_if_update({"username": "john"}, user_details("john", "13/03/2021"), posts)

print("inserted")
print(posts.find_one({"username": "john"}))

check_if_update({"username": "john"}, user_details2("john", "13/03/2021", "Lemon drizzle"), posts)

print("Results:")
print(posts.find_one({"username": "john"}))

It is available as a gist

Comments

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.