mongoengine
mongoengine copied to clipboard
get_or_create alternative
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?
Also, modify does not fill default values -- I have to this by myself... Looks there is no alternative.
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 thanks for the info. Should I close this issue then?
Leave it open and I'll look at a solution for default values.
Any word on this feature? upsert_one dealing with defaults that is
@BeardedSteve can we insert default values now?
@qasimjaved could you summarize the remaining issue and give a sample code snippet with the actual and expected result?
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.
Thanks @qasimjaved, I modified your content slightly for better readability.
ok. great ! @wojcikstefan Is this issue fixed now about 'default values insertion' ???
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.
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.
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/
Possible duplicate with respect to upsert_one() and default values and required fields: https://github.com/MongoEngine/mongoengine/issues/2694