teechap
teechap

Reputation: 861

How can I create a MongoEngine document with referenced documents that are already in the database?

I already have a class of documents stored in my (Flask-MongoEngine) database, and I already have their unique id. My actual example is more complicated, but let's say it looks like this:

class Stuff(Document):
    stuffstuff = StringField()

I'd like to make a collection of Stuff instances from Stuffs already in my database. Let's say I want to make a new instance of the class below from Stuff instances currently in my database.

class StuffsCollection(Document):
    lotsofstuffs = ListField(ReferenceField(Stuff))

In the ReferenceField documentation, it looks like the only way to create a StuffsCollection instance is to first create instances of Stuff, then pass them in as keyword arguments. For example:

a_thing = Stuff(stuffstuff="here's a thing")
a_thing.save()
some_things = StuffsCollection(lotsofstuffs=[a_thing])
some_things.save()

Since I already have the unique ids that reference my Stuff instances, can I just tell MongoEngine to use those existing Stuffs as keyword arguments in a new StuffsCollection? It seems like this would be more efficient than querying the database for each document, then creating a new instance of that document, then passing each into my new ListField.

Upvotes: 1

Views: 892

Answers (1)

Nicolas Cortot
Nicolas Cortot

Reputation: 6701

You need to pass DBRef objects:

from bson import DBRef, ObjectId

a_id = ObjectId('somevalidid')
a_ref = DBRef('stuff', a_id)

some_things = StuffsCollection(lotsofstuffs=[a_ref])
some_things.save()

MongoEngine stores a ReferenceField using either DBRef or ObjectID. The 'stuff' argument to DBRef will simply be ignored if the field is configured with dbref=False. Otherwise, this must be the name of the collection for the Stuff objects.

However, you need to pass DBRef objects to the constructor in both cases because of the way the validation is implemented in ReferenceField.

Upvotes: 2

Related Questions