Search code examples
pythonpython-3.xmongodbmongoengineflask-mongoengine

How do I update if exist and insert if not using mongoengine (python)


It is really absurd how mongoengine has such arcane documentation. I am trying to do a simple (update if exists query) based on a few columns/fields. What I mean by that is

if fieldA has valueA and 
   fieldB has valueB and 
   fieldC has valueC 
then
update fieldD with newValueD, 
       fieldE with newValueE

I could do it in the method mentioned below but I am pretty sure there is a really simple upsert syntax where if I mention the fields and values then it matches it across the collection, updates if they match and inserts if they don't

def __generateRemoteData(data):
    """
    Utils function to add remote data to Mongo

    """
    for datum in data:
        query = RemoteGraph.objects(
            Q(fieldA=datum.get('fieldA')) and
            Q(fieldB=datum.get('fieldB')) and
            Q(fieldC=datum.get('fieldC')) and
            Q(fieldD=datum.get('fieldD')) and
            Q(fieldE=datum.get('fieldE')) and
            Q(date=datum.get('date'))
        )
        if not query:
            RemoteGraph(
                fieldA=datum.get('fieldA'),
                fieldB=datum.get('fieldB'),
                fieldC=datum.get('fieldC'),
                fieldD=datum.get('fieldD'),
                fieldE=datum.get('fieldE'),
                date=datum.get('date'),
                fieldF=datum.get('fieldF'),
                fieldG=datum.get('fieldG'),
            ).save()
        else:
            query.update(
                set__fieldF=datum.get('fieldF'),
                set__fieldG=datum.get('fieldG'),
            )

Looking for a more pythonic way to do this.

I have looked into upsert, insert, modify, save, update, update_one


Solution

  • First of all Q() combines only with bitwise operators. And the meaning of Q is in combining & and | operators. Detailed here

    There is a special option upsert=True of the QuerySet::update method. Upsert – force an insertion of a new document if RemoteGraph.objects(a=val_a, b=val_b, c=val_c, date=date) founds no one document.

    RemoteGraph.objects(
        a=val_a, b=val_b, c=val_c, date=date
    ).update(
        a=val_a, b=val_b, c=val_c, date=date
    )
    

    Also there are [QuerySet::modify][3] and QuerySet::update_one method, they could upsert new document too, but unlike of QuerySet::update, they will update only first document from QuerySet.

    And finally there is a QuerySet::upsert_one. The name says it all. One noticeable distinction it raises an Exception if the QuerySet contains more than one document. Actually QuerySet::update_one and QuerySet::upsert_one are small wrappers over QuerySet::update