Search code examples
javascriptmongodbmongoosenosqlgraphlookup

How to $graphLookup with dynamic parent references in Mongoose


Let's assume I'm making a react app to manage what's in my restaurant's fridge. I have three collections:

  • Refrigerators (contains jars or food items)
  • Jars (contains jars or food items; exists in refrigerators or other jars)
  • Food Items (exists in jars or fridge)

Refrigerators:

[{
   "name": "abc",
   "temp": 23,
}, ...]

Jars:

[{
   "name": "jar1",
   "parent": 
   {
      "type": "jar",
      "id": "id_of_parent_jar"
   }
}, {
   "name": "jar2",
   "parent": 
   {
      "type": "refrigerator",
      "id": "id_of_parent_refrigerator"
   }
},
 ...]

Food Items:

[{
   "name": "jar1",
   "parent": 
   {
      "type": "jar",
      "id": "id_of_parent_jar"
   }
},
 ...]

A problem arises in any situation where we are using all three collections:

food -> jar -> fridge

There is no way to tell graphLookup to change the from field when the jar parent is a fridge. To further complicate things:

food -> jar -> jar -> fridge

introduces another problem; you cannot assume that depth 1 will be a jar, and depth 2 will be a fridge. Depth 1+n could be any number theoretically until we hit a refrigerator reference.

How would you get graphLookup to dynamically change the from collection based on the parent.type field of either the jar or food_item?


Solution

  • There's no great way to do this in Mongo. Instead, I opted to implement an "array of ancestors" model that would not have to regressively query.

    https://www.mongodb.com/docs/manual/tutorial/model-tree-structures-with-ancestors-array/

    Instead, each time a new object is made, the object will simply append itself to a copy of it's parent's ancestor array, expanding it's ancestor array by n + 1. Each time a further child is created, this process repeats; no need for regressive querying as the previous tree position is stored.

    Note that this makes moving tree items around very hard

    If you need to move things around, you'd have to either:

    1. Implement an algorithm to update a parent's position and all of it's children's array of ancestors (costly)
    2. Make a separate collection where each document references either a food, jar, or fridge, and use graphLookup there, as everything is in the same collection.