3

In the guide for materialized path tree structures at mongodb docs they show a simple example of how to structure data to support simple querying:

db.categories.insert( { _id: "Books", path: null } )
db.categories.insert( { _id: "Programming", path: ",Books," } )
db.categories.insert( { _id: "Databases", path: ",Books,Programming," } )
db.categories.insert( { _id: "Languages", path: ",Books,Programming," } )
db.categories.insert( { _id: "MongoDB", path: ",Books,Programming,Databases," } )
db.categories.insert( { _id: "dbm", path: ",Books,Programming,Databases," } )

This works fine as long as _id is unique for each item. In our case, we are designing a course structure, which has to support SEO:able URLs such as /course-a/lesson-1/introduction. The data design must support duplicates (e.g. multiple courses can have a lesson called "introduction"):

  • Course A
    • Introduction (lesson)
      • Part 1 (lesson)
      • Part 2 (lesson)
    • Background (lesson)
    • ... (lesson)
  • Course B
    • Introduction (lesson)
    • Why this works (lesson)
    • ... (lesson)

Our current solution is to have the lessons created using the materialized path design. This is when we realized it won't work with duplicate lesson ids. But before throwing it all away, I'd like to ask for your advice.

Is there any way to design this to support our problem using materialized paths?

Mickel
  • 6,658
  • 5
  • 42
  • 59
  • FYI: By default the index for `_id` (`_id_`) is non-unique, so there's technically no Duplicate Key problem. Now, when combining both `_id` and `path` each document will be unique; however, with this "multikey" approach you _must always_ query the tree with an absolute path. – zamnuts Aug 29 '14 at 13:37
  • @zamnuts: The index on `_id` is unique by default. If the whole path is unique, you could set your `_id` field to be essentially the whole path to the documents: `"_id" : { "name" : "introduction", "path" : ",course-a,lesson-1," }`. I think this should preserve the benefits of the materialized path tree for you. – wdberkeley Aug 29 '14 at 15:14
  • @wdberkeley you are correct, my bad... `use test; db.createCollection('idtest'); db.idtest.getIndexes();` yields: `[{"v":1,"key":{"_id":1},"name":"_id_","ns":"test.idtest"}]`. doesn't show that it is unique, but will fail with E11000 duplicate key error... deceiving. good work-around. – zamnuts Aug 30 '14 at 02:55
  • @wdberkeley that's probably a good solution. I also figured we could embed the lessons in the course-document, using an ObjectId-reference and including the materialized path in course.lessons[], like so: course.lessons[{ _lesson: ObjectId, slug: '...', path: '...' }]. However, I guess that would require projections or client-side code to query the tree. – Mickel Aug 30 '14 at 08:23

0 Answers0