mongodbdoctrine-odmdoctrine-mongodb

Querying discriminated collection by ID using Doctrine MongoDB


How can I query for an object knowing only its ObjectId using Doctrine MongoDB? Queries by id, using $dm->findOneBy(array('id' => $id)) will only return a result for one of the discriminated document types, but not others. Querying via the command line, e.g. db.documents.find({ "_id": ObjectId(...) }); returns the expected row.

Edit: The issue appears to be that, if I don't know the type of document I'm querying for and I'm using a custom repository, the document name that is used is tied to the class name of only one of the two document classes (hence returning 0 results for other types of documents). This generally makes sense, because if I don't know what type of document I'm looking for how should Doctrine? Given a discriminated collection, is there any way to automagically use the right document name in the repository without explicitly telling doctrine?

See below for an abstraction of the problem.

Thanks!


I have a set of discriminated documents living in the same documents collection, discriminated by their type field e.g.

{
  "_id" : ObjectId("510fdb6c91a4cb4c25000000"),
  "name" : "Contract",
  "type" : "document"
}
{
  "_id" : ObjectId("510fdb6c91a4cb4c25000001"),
  "name" : "Tutorial",
  "length_min": "60"
  "type" : "video"
}
...

My mapping for both Document and Video classes looks like:

<!-- "Doc" Document mapping -->
<doctrine-mongo-mapping ...>
  <document name="Doc" collection="documents" repository-class="DocRepository">
    <discriminator-field fieldName="type" />
    <discriminator-map>
      <discriminator-mapping value="document" class="Doc" />
      <discriminator-mapping value="video" class="Video" />
    </discriminator-map>

    <field fieldName="id" id="true" />
    <field fieldName="name" field="name" type="string" />
  </document>
</doctrine-mongo-mapping>

<!-- "Video" Document mapping -->
<doctrine-mongo-mapping ...>
  <document name="Video" collection="documents" repository-class="DocRepository">
    <discriminator-field fieldName="type" />
    <discriminator-map>
      <discriminator-mapping value="document" class="Doc" />
      <discriminator-mapping value="video" class="Video" />
    </discriminator-map>

    <field fieldName="id" id="true" />
    <field fieldName="name" field="name" type="string" />
    <field fieldName="length_min" field="length_min" type="int" />
  </document>
</doctrine-mongo-mapping>

Solution

  • In your case, I see only one solution, without resorting to creating some additional wrapper repositories like Sean Quinn above suggested.

    I'd use a single collection for all the documents that are discriminated - if you don't have a base class for all of the classes you are storing, I'd add some abstract class. It is described in Doctrine documentation about inheritance mapping. Long story short, you use only one collection, some field informs about the class of a stored object, and after querying this repository you get an object of a proper class.

    To use single collection inheritance mapping, you add inheritance-type="SINGLE_COLLECTION" attribute to a top-class document tag.