Upserting document and returning what changed or what was inserted

I’m trying to get the data that was updated or inserted into the collection. This is for implementing version history (change stream isn’t a good fit for our use case, so we need to use custom solution).

Basically when the document is initially added, the full document is added to the version history, but any updates afterwards will only include fields that changed from the previous version.

This is the closest I’ve gotten:

# Code

for item in import_data:
    result = collection.update_one({"name": item["name"], "serial_number": item["serial_number"]}, {"$set": item}, upsert=True)

# Printed when document was inserted:

	'n': 1,
	'upserted': ObjectId('6571a3d450ed09ae8776e2eb'),
	'nModified': 0,
	'ok': 1.0,
	'updatedExisting': False

# Printed when document was updated:

	'n': 1,
	'nModified': 1,
	'ok': 1.0,
	'updatedExisting': True

Of course this is something that I can do manually in python, but if there is already a way to get the data from the update/insert query without having to do another query, it would be better. It would be simpler and probably faster too.

There is already a way to get the delta that changed and that’s using change streams. Can you briefly explain why change streams are not a good fit?

The only alternative I can think of at the moment would be to use find_one_and_update() which returns the new document after the update is applied. However, note that update_one() has better performance than find_one_and_update so there will still be a cost.

At least based on my understanding change streams don’t have user tracking or if they did, it was on database level. In our use case the users access the database through sending HTTP queries to the endpoint, so we’d have to log that user as the user who made the change and not the database level user, which in this case is the backend.

Would update_one() and then find_one() to get the new document be more optimal to use than find_one_and_update()?