mongoengine icon indicating copy to clipboard operation
mongoengine copied to clipboard

get_or_create alternative

Open warvariuc opened this issue 9 years ago • 14 comments
trafficstars

I am migrating from MongoEngine 0.8.* to .10.* I have this code:

obj, created = Model.objects.get_or_create(...)
if created:
    obj.a_field = ...

I am trying to replace the deprecated get_or_create with modify. The problem is that it looks user unfriendly. I see two ugly ways to determine if the object was updated or created:

obj = Model.objects(...).modify(upsert=True, new=False, set__...)
if obj is None:
    # have to fetch the created document -- code duplication and additional request to the DB
    obj = Model.objects.get(...)

or

obj = Model.objects(...).modify(upsert=True, new=True, set__..., set_on_insert__is_new=True)
if obj.is_new:
    # have to create `Model.is_new` field just for the sake of this case
    ....

Do I understand correctly there is no elegant alternative for get_or_create?

warvariuc avatar Nov 30 '15 13:11 warvariuc

Also, modify does not fill default values -- I have to this by myself... Looks there is no alternative.

warvariuc avatar Nov 30 '15 16:11 warvariuc

I have had a PR merged #1167 based on this issue #1157

Version 0.10.4 will have an upsert_one method which may solve this for you.

obj = Model.objects.upsert_one()

I agree however that the defaults are still not dealt with. I may look at updating this function to include that feature.

BeardedSteve avatar Nov 30 '15 22:11 BeardedSteve

@BeardedSteve thanks for the info. Should I close this issue then?

warvariuc avatar Dec 01 '15 07:12 warvariuc

Leave it open and I'll look at a solution for default values.

BeardedSteve avatar Dec 01 '15 09:12 BeardedSteve

Any word on this feature? upsert_one dealing with defaults that is

ScriptProdigy avatar Jun 07 '17 17:06 ScriptProdigy

@BeardedSteve can we insert default values now?

qasimjaved avatar Jul 13 '17 12:07 qasimjaved

@qasimjaved could you summarize the remaining issue and give a sample code snippet with the actual and expected result?

wojcikstefan avatar Jul 13 '17 13:07 wojcikstefan

Thanks for quick response!

class TestCollection(Document):
	bool_field = BooleanField(default=False)
	test_str = StringField(null=True)

Input operation is:

TestCollection.objects(test_str='1').upsert_one(test_str='1')

Expected output:

{ "_id" : ObjectId("5967635223a1fc4817ae05a6"),  "bool_field" : false, "test_str" : "Hello" }

Actual output:

{ "_id" : ObjectId("5967635223a1fc4817ae05a6"),  "test_str" : "Hello" }

** Please let me know if you need further information.

qasimjaved avatar Jul 13 '17 13:07 qasimjaved

Thanks @qasimjaved, I modified your content slightly for better readability.

wojcikstefan avatar Jul 13 '17 13:07 wojcikstefan

ok. great ! @wojcikstefan Is this issue fixed now about 'default values insertion' ???

qasimjaved avatar Jul 13 '17 13:07 qasimjaved

It most likely isn't, though I haven't dove into the issue yet. Will do soon. It would be helpful if you submitted a PR with a failing unit test.

wojcikstefan avatar Jul 13 '17 13:07 wojcikstefan

How to use this with PointField?


class Location(db.Document):
    location_name = db.StringField(required=True)
    geoCoords = db.PointField()

Location.objects(geoCoords=loc["geoCoords"]).upsert_one(location_name=loc["location_name"], geoCoords=loc["geoCoords"])
#loc["geoCoords"] = [77.6309395,12.9539974]

It just creates new entry, even if I pass the same values.

JamesPJ avatar Sep 22 '17 13:09 JamesPJ

is this of any help for a new alternative? https://stackoverflow.com/questions/16358857/mongodb-atomic-findorcreate-findone-insert-if-nonexistent-but-do-not-update

and see the docs: https://docs.mongodb.com/manual/core/transactions/

tks-socius avatar Dec 20 '21 14:12 tks-socius

Possible duplicate with respect to upsert_one() and default values and required fields: https://github.com/MongoEngine/mongoengine/issues/2694

manuel-koch avatar Oct 12 '22 11:10 manuel-koch