skip to Main Content

I’m having a hard time struggling how to find out how to upsert in MongoDB using mongoengine.

My current inserting code looks like this:

for issue in data['issues']:

    doc = Issue(
        key=issue['key'],
        title=issue["fields"]["summary"],
        type=issue["fields"]["issuetype"]["name"],
        status=issue["fields"]["status"]["name"],
        assignee=issue["fields"]["assignee"]["displayName"] if issue["fields"]["assignee"] else None,
        labels=issue["fields"]["labels"],
        components=[c['name'] for c in issue["fields"]["components"]],
        storypoints=int(issue["fields"]["customfield_10002"]) if issue["fields"]["customfield_10002"] else 0,
        sprints=[x['name'] for x in sprint_dict] if sprint_dict != None else None,
        updated_at=datetime.utcnow(),
        created=issue["fields"]["created"]
    )
    
    doc.save()

This of course only saves, but I’ve tried so many variants of update with upsert=True etc that I found, and none of them worked.

3

Answers


  1. It’s here https://docs.mongoengine.org/apireference.html#mongoengine.queryset.QuerySet.update_one

    Assuming the unique Id is key and you want to overwrite all fields on update, it must be

    Issue.objects(key=issue['key']).update_one(upsert=True,
        set__key=issue['key']
        set__title=issue["fields"]["summary"],
        set__type=issue["fields"]["issuetype"]["name"],
        set__status=issue["fields"]["status"]["name"],
        set__assignee=issue["fields"]["assignee"]["displayName"] if issue["fields"]["assignee"] else None,
        set__labels=issue["fields"]["labels"],
        set__components=[c['name'] for c in issue["fields"]["components"]],
        set__storypoints=int(issue["fields"]["customfield_10002"]) if issue["fields"]["customfield_10002"] else 0,
        set__sprints=[x['name'] for x in sprint_dict] if sprint_dict != None else None,
        set__updated_at=datetime.utcnow(),
        set__created=issue["fields"]["created"]
    )
    

    components and sprints seem to be lists, so if you want to add to the lists rather than overwrite them, you should use

    push_all__components=[c['name'] for c in issue["fields"]["components"]]
    push_all__sprints=[x['name'] for x in sprint_dict] if sprint_dict != None else []
    

    List of all modifiers is here:
    https://docs.mongoengine.org/apireference.html#mongoengine.queryset.QuerySet.update_one pick the ones that suit your idea of upserting.

    Login or Signup to reply.
  2. I believe what you are doing is already correct. The documentation of the .save() method says:

    Save the Document to the database. If the document already exists, it will be updated, otherwise it will be created. Returns the saved object instance.

    Which is the definition of an upsert. Looking at the source code, it seems that it actually does not use mongo’s upsert operation, but it achieves the same.

    Login or Signup to reply.
  3. To upsert the Issue document in the code you provided, you can use the update_one() method with the upsert=True option after creating the doc object. Here’s an example:

    from mongoengine import connect, Document, StringField, ListField, IntField, DateTimeField
    
    # define the Issue document
    class Issue(Document):
        key = StringField(required=True, unique=True)
        title = StringField(required=True)
        type = StringField(required=True)
        status = StringField(required=True)
        assignee = StringField()
        labels = ListField(StringField())
        components = ListField(StringField())
        storypoints = IntField(default=0)
        sprints = ListField(StringField())
        updated_at = DateTimeField()
        created = DateTimeField()
    
    # connect to MongoDB
    connect('mydb')
    
    # iterate over the issues in the data object
    for issue in data['issues']:
        # create an Issue object for each issue
        doc = Issue(
            key=issue['key'],
            title=issue["fields"]["summary"],
            type=issue["fields"]["issuetype"]["name"],
            status=issue["fields"]["status"]["name"],
            assignee=issue["fields"]["assignee"]["displayName"] if issue["fields"]["assignee"] else None,
            labels=issue["fields"]["labels"],
            components=[c['name'] for c in issue["fields"]["components"]],
            storypoints=int(issue["fields"]["customfield_10002"]) if issue["fields"]["customfield_10002"] else 0,
            sprints=[x['name'] for x in sprint_dict] if sprint_dict != None else None,
            updated_at=datetime.utcnow(),
            created=issue["fields"]["created"]
        )
    
        # upsert the document in the database
        doc.update_one(set__key=doc.key, upsert=True)
    

    In this example, we define the Issue document and connect to the MongoDB database. We then iterate over the issues in the data object, creating an Issue object for each issue. After creating the doc object, we use the update_one() method with the set__key=doc.key parameter to update the document with the specified key, or insert it if it doesn’t exist (upsert=True). This will ensure that each document in the database corresponds to a unique issue key.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search