Multi-level Array and Mongo collection with meteor methods

Hi everyone :smile: I’m actually on a gantt diagram and I have to work on a Tree style hyerarchy on my mongo collection to be able to move any tasks inside any other tasks and to have multiple level child/mother relations without any limits… It have to be easy to update or move any node so I though that a typical Tree style could perform pretty well

So this is actually what I have on my mockup :

Tasks collection
{
            { "_id" : "y9bi6GEEjfaKJyDNr", "name" : "PRoject 1", "personnage" ... }
            { "_id" : "TY6prrpfwryTug8fr", "name" : "PRoject 2", "personnage" : "aggg", "quantity" : 36, ... }
            { "_id" : "JdxJo2ghrzBCBYfiT", "name" : "PRoject 3", "personnage" : "agd", "quantity" : 29, ...}
}

This is what I would like to have :

New tasks collection experimental mapping
{
    'tree': {
                {"_id": "y9bi6GEEjfaKJyDNr", "number_of_childs" : 0, "childs": ""} 
                {"_id": "TY6prrpfwryTug8fr", "number_of_childs" : 0, "childs": ""} 
                {"_id": "JdxJo2ghrzBCBYfiT",
                "number_of_childs" : 3,
                "childs": { {"_id": "FSet4LQRqAwSLyqRA", "number_of_childs" : 0, "childs": ""} 
                                {"_id": "hMDCw5bgvHrkzqJ94" 
                                "number_of_childs" : 1
                                "childs": {"_id": "kvfXpmkd7zu9K38Qv""number_of_childs" : 0,"childs": ""} }
                }
                {"_id": "YbYuaoCqGkD72cJz4", "number_of_childs" : 0, "childs": ""} 
                {"_id": "WaJeidMGDMmgma9gT", "number_of_childs" : 0, "childs": ""} 
                {"_id": "vPLhPa7GQNiCEWrhd","number_of_childss" : 0,"childs": ""} 
                {"_id": "YDRknrt3tyYnG3Kd7",
                "number_of_childs" : 2,
                "childs": {"_id": "SKK3zqHbirkN3xaQZ","number_of_childss" : 0,"childs": ""}
                              {"_id": "rd9gj44jbqoDFnJGt","number_of_childs" : 0,"childs": ""} 
            }
    },
    "tasks":{
            { "_id" : "y9bi6GEEjfaKJyDNr", "name" : "PRoject 1", "personnage" ... }
            { "_id" : "TY6prrpfwryTug8fr", "name" : "PRoject 2", "personnage" : "aggg", "quantity" : 36, ... }
            { "_id" : "JdxJo2ghrzBCBYfiT", "name" : "PRoject 3", "personnage" : "agd", "quantity" : 29, ...}
....
    }
}

So I would like to map the Tree in a sperate sub Collection, I’m new on the world of noSql database so I’m a little confused.
What do you think of my idea? The fact that there is a non duplicable ID at each lvl make it easier to manage.

But how the insert and update Meteor methods will look like with mutiple lvl sub collections? Is it possible to have this? My brain cannot see out of the picture for now :sweat_smile:

I think you should have a look into arrayFilters:

They let you select something precisely according to variables that can be deeply nested.

1 Like

it’s possible to have multilevel nesting with MongoDB, but it comes with the cost of performance. So I’d suggest that if you are at the initial stage of you then you should consider remodeling your schema and avoid multilevel nesting if possible.

In general, you can represent the parent/child relationship in the following manner.

{ "_id" : 1, "parent" : null }
{ "_id" : 2, "parent" : null }
{ "_id" : 3, "parent" : 1 }
{ "_id" : 4, "parent" : 2 }

Here, documents 1 & 2 are parent documents and 3 & 4 are their child documents.

Or if parent and child have a different schema you can break it down into two or multiple separate collections.

This article provides a brief explanation of how to model parent-child relations in MongoDB.

1 Like

The problem I see here is in “without any limits”.
Ok, let’s say:

  • you have a Project with { _id: 123, … } (In Projects collection)
  • you have a task with { _id: 345, projectId: 123 } (In Tasks collection)
  • you have a task with { _id: xxx, projectId: 123 } (In Tasks collection)
  • you have a date/time with { _id: 567, projectId: 123, taskId: 345 } (In Calendars collection)
  • same for any other type of resource - should live in its own resource type collection.

Then you can have 1000 tasks in a Project, 1000 dates/times or other resources.
The parent/child relationship is given by the ids you link.

When you query the DB you think this way:
Give me the project with this projectId (or project name etc). Give me all the tasks that have this projectId.
Map over all the tasks, get me an array of all taskIds and give me all the schedules for those tasks.

const projectId = Projects.findOne({ name: 'ProjectOne' }, {fields: { _id: 1 } })?._id
const taskIds = []
Tasks.find({ projectId }, {fields: {/* ... */}} ).forEach(task => taskIds.push(task._id)) // here you work with a cursor, you didn't actually transferred your tasks from DB to your server.
// if the next line does not wait for the previous query, make it dependent on the index of forEach
Calendars.find({ taskId: {$in: taskIds } }).fetch()
// etc

Either return results and serialize on the client or serialize on the server and build your tree before you return to the client.
return {
   project: {},
   tasks: [], // if Array (Collection.find()), do the .fetch()
   schedules: []
}

MongoDB offers some aggregations for searches which may be very useful in your case.

2 Likes

Thank you so much for you help and the time you took for your responses. Sorry for the late reply :neutral_face:

@ivo Thank you for the link, I already looked into the doc but did’nt found exactly what I was looking for.

@distalx Yup Maybe making a flat array is the best way, thats what I tried the last days but it take a little more time to compute. The probleme with this is the fact that in my Gantt diagram, we could change the position of each task and move them from a “group” to another. So I’m afraid that it will ask some ressources to update all the lines individually. With the isolated tree shape collection the idea was to update it entirely at each changes but finally, with a flat array I could do exactly the same : Making a clone collection with only the child/parents and ID of each tasks, and give the possibility to update the entire collection at once, it will be also ligther than a tree version, I really have to finish my test.

@paulishca Thank you for your complete answer! I need some time to compute your idea, I also have to see the instant update part with some ressources saving. The update might be a little more complicate than the findOne, let me see this in detail :slight_smile:

1 Like