hi,
I got some trouble in using mixin fields, here is the sample code:
>>> from mongoengine import Document
>>> from mongoengine import MapField, ListField, ReferenceField
>>> class R(Document):
... pass
...
>>> class T(Document):
... rs = MapField(field=ListField(ReferenceField(R)))
...
>>> T.objects
[]
>>> t = T()
>>> t.rs
{}
>>> t.rs['rs1'] = [R()]
>>> t.rs
{'rs1': [<R: R object>]}
>>> t.rs['rs1'][0].save()
<R: R object>
>>> t.save()
<T: T object>
>>> t
<T: T object>
>>> T.objects
[<T: T object>]
>>> T.objects[0].rs
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\tmp\venv\lib\site-packages\mongoengine\base\fields.py", line 279, in __get__
value, max_depth=1, instance=instance, name=self.name
File "C:\tmp\venv\lib\site-packages\mongoengine\dereference.py", line 76, in __call__
self.reference_map = self._find_references(items)
File "C:\tmp\venv\lib\site-packages\mongoengine\dereference.py", line 115, in _find_references
reference_map.setdefault(item.collection, set()).add(item.id)
TypeError: unhashable type: 'list'
I want to use MapField to mapping key=String, value=List[Ref(Document)], save into mongodb is work, but can't retrieve it.
I tried to trace to figure out something, but I'm failed too. :joy_cat:
I've confirmed this, but have not yet hunted down the reason. Additional notes:
The problem is also with parent DictField; so this is not a MapField problem per se.
The problem is specifically with a ListField containing ReferenceField. So,
class T(Document):
rs = MapField(field=ListField(StringField()))
works fine. And
class T(Document):
rs = MapField(field=ReferenceField(R))
Also works fine.
Until this is resolved, here is a temporary work-around:
class R(Document):
pass
class TRMap(EmbeddedDocument):
rl = ListField(ReferenceField(R))
class T(Document):
rs = MapField(field=EmbeddedDocumentField(TRMap))
t = T()
m = TRMap(rl=[R()])
t.rs['rs1'] = m
t.rs['rs1'].rl[0].save()
t.save()
print T.objects[0].rs['rs1'].rl[0]
Just pushed a PR to fix this, note that the issue was also occuring with DictField and wasn't present if you use ReferenceField(dbref=True). See below:
class Doc(me.Document):
s = me.StringField()
class Simple(me.Document):
mapping1 = me.DictField(field=me.ListField(me.ReferenceField(Doc, dbref=True)))
mapping2 = me.DictField(field=me.ListField(me.ReferenceField(Doc, dbref=False)))
doc = Doc(s='aa').save()
Simple(mapping1={'test': [doc]}, mapping2={'test': [doc]}).save()
s = Simple.objects().first()
s.mapping1 # {'test': [<Doc: Doc object>]}
s.mapping2 # raises TypeError: unhashable type: 'list'
Most helpful comment
Until this is resolved, here is a temporary work-around: