Rahul Tandon
Rahul Tandon

Reputation: 55

Pymongo Find & Update problems

Background I'm making an application which takes an input through a Discord bot and then puts the input in a Google Document. During that process, I'm using Flask with Pymongo to find documents whose isNew property is set to true and send it back to Google Docs script. After that's done I want to set the isNew property of the documents to set to false. Alternatively, I can set the isNew to false before I send, since i can't call a function successfully, after I have returned the response in Flask.

Based on what I've experimented with, whenever I get new documents using a <CollectionName>.find() request, and tried to update the isNew property subsequently using a CollectionName.update_many() command, it results in the variable storing the original find command documents to go blank.

Code Attempts: 1. update many while trying to return new documents

import pymongo

# mongodb db connection string
connectionString = ('mongodb://localhost:27017')

client = pymongo.MongoClient(connectionString)
db = client['tempBotDB']

# 3 types of questions: quiz, cross, hunt
# separate collections for each type of strings

quizQs = db['quizQs']
crossQs = db['crossQs']
huntQs = db['huntQs']

# Properties of a question: isnew, type, question, answer


def saveQ(qObj):    # Saves a question to the db

    qType = qObj.get('type')

    # creating own qObj
    q = {
        'question': qObj.get('question'),
        'answer': qObj.get('answer'),
        'isNew': bool(True)
    }

    if qType == 'quiz':
        result = quizQs.insert_one(q)
    elif qType == 'cross':
        result = crossQs.insert_one(q)
    elif qType == 'hunt':
        result = huntQs.insert_one(q)
    else:
        result = ('Error: "type" of question can only be'
                  'one of : cross, hunt, quiz')
    return result


def getQs(qType):   # Gets all the questions by given type
    if qType == 'quiz':
        result = quizQs.update_many(
            {'isNew': bool(True)},
            {'$set': {'isNew': bool(False)}},
            {returnOriginal: True}
         )
        print(result)

    else:
        result = ('Error: "type" of question can only be'
                  'one of : cross, hunt, quiz')


getQs('quiz')

Error: NameError: name 'returnOriginal' is not defined Also tried with returnNewDocument instead of returnOriginal. But got: NameError: name 'returnNewDocument' is not defined

  1. Using a find followed by an update within the same function
def getQs(qType):   # Gets all the questions by given type
    if qType == 'quiz':

        selector = {'isNew': False}
        modifier = {'$set': {'isNew': True}}

        result = quizQs.find(selector)
        #fakeRes = quizQs.update_many(selector, modifier)

        print('res', result)
        for i in result:
            print('result', i)
        #print('fakeres', fakeRes)
        # for i in fakeRes:
        #     print('FakeRes', i)

    else:
        result = ('Error: "type" of question can only be'
                  'one of : cross, hunt, quiz')

If I uncomment the update command, the result of the find command becomes uniteratable (I get an error message), which to the best of my knowledge means that it's empty. Here's what happens:

def getQs(qType):   # Gets all the questions by given type
    if qType == 'quiz':

        selector = {'isNew': False}
        modifier = {'$set': {'isNew': True}}

        result = quizQs.find(selector)
        fakeRes = quizQs.update_many(selector, modifier)

        print('res', result)
        for i in result:
            print('result', i)
        print('fakeres', fakeRes)
        for i in fakeRes:
            print('FakeRes', i)

    else:
        result = ('Error: "type" of question can only be'
                  'one of : cross, hunt, quiz')

I get an the following output:

res <pymongo.cursor.Cursor object at 0x10e34ca50>
fakeres <pymongo.results.UpdateResult object at 0x10e35bfa0>
Traceback (most recent call last):
  File "db.py", line 63, in <module>
    getQs('quiz')
  File "db.py", line 55, in getQs
    for i in fakeRes:
TypeError: 'UpdateResult' object is not iterable

Notice how iterating through the result object did not print anything, pointing to the fact that it goes empty.

So, to conclude, my main question is: How do I successfully find and update multiple documents in mongodb, while retrieving the update documents, OR just the found documents (not updated) [EITHER of them will work as i won't need to access the property I update]

Lastly, would it be logical to first do a find and then update_one on each document while generating a list of dictionaries of the updated documents and then finally returning that list to the user?

I'd really appreciate any help.

Upvotes: 1

Views: 1982

Answers (1)

Belly Buster
Belly Buster

Reputation: 8814

There's a few ways to do this, but you can't get the list of updated documents from an update_many - Mongo doesn't support that.

So your best approach is:

for record in db.mycollection.find({'isNew': False}):
    result = db.mycollection.update_one({'_id': record['_id']}, {'$set': {'isNew': True}})
    print(record)
    # Add in logic here  to assemble records for return to the user

Upvotes: 2

Related Questions