MongoEngine / mongoengine

A Python Object-Document-Mapper for working with MongoDB
http://mongoengine.org
MIT License
4.2k stars 1.23k forks source link

get_or_create alternative #1171

Open warvariuc opened 8 years ago

warvariuc commented 8 years ago

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 commented 8 years ago

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

BeardedSteve commented 8 years ago

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.

warvariuc commented 8 years ago

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

BeardedSteve commented 8 years ago

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

ScriptProdigy commented 7 years ago

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

qasimjaved commented 7 years ago

@BeardedSteve can we insert default values now?

wojcikstefan commented 7 years ago

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

qasimjaved commented 7 years ago

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.

wojcikstefan commented 7 years ago

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

qasimjaved commented 7 years ago

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

wojcikstefan commented 7 years ago

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.

JamesPJ commented 6 years ago

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.

tks-socius commented 2 years ago

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/

manuel-koch commented 1 year ago

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