I have a collection in which data is stored in tree structure. Sample:
[
{
"_id": "entry1Id",
"name": "entry1",
"dependency": "entry2"
},
{
"_id": "entry2Id",
"name": "entry2",
"dependency": "entry3"
},
{
"_id": "entry3Id",
"name": "entry3",
"dependency": "entry4"
},
{
"_id": "entry4Id",
"name": "entry4",
"dependency": "entry5"
},
{
"_id": "entry5Id",
"name": "entry5",
"dependency": ""
}
]
The depth is not defined but wont be circular.
Now i want a query to pass a name and get that item and all the nodes below that.
I tried doing it using multiple DB calls and its working, but i want to improve it.
'use strict';
module.exports = ({ $db }) => {
return async (req, res, next) => {
try {
const name = req.query.name;
const data = await getEntity($db, name);
return res.status(200).json({
success: true,
data
});
} catch (error) {
return next(error)
}
}
}
const getEntity = async ($db, id) => {
const entity = await $db.models.Entity.findOne({ name }, { name: true, dependency: true });
if (entity && entity.dependency) {
entity.dependency = await getEntity($db, entity.dependency);
}
return entity;
}
But i expect the output should be more like tree.
{
"_id": "entry1Id",
"name": "entry1",
"dependency": {
"_id": "entry2Id",
"name": "entry2",
"dependency": {
"_id": "entry3Id",
"name": "entry3",
"dependency": {
"_id": "entry4Id",
"name": "entry4",
"dependency": {
"_id": "entry5Id",
"name": "entry5",
"dependency": ""
}
}
}
}
}
I also tried $graphLookup but the output is not what i expect
const getEntityWithDependencies = async ($db, name) => {
const aggregationPipeline = [
{
$match: { name }
},
{
$graphLookup: {
from: 'entities', // Use the actual name of your collection
startWith: '$dependency',
connectFromField: 'dependency',
connectToField: 'name',
as: 'dependencies',
}
}
];
const result = await $db.models.Entity.aggregate(aggregationPipeline).exec();
return result.length > 0 ? result[0] : null;
}
The output i got using above is something like
{
"_id": "entry1Id",
"children": [
{
"_id": "entry2Id",
"dependency": "entry3Id",
"name": "entry2"
},
{
"_id": "entry3Id",
"dependency": "",
"name": "entry3"
}
],
"dependency": "entry2Id",
"name": "entry1"
},
Try some loop on top of graphLookup like:
'use strict';
const helper = require('../../../utils/helper');
module.exports = ({ $db }) => {
return async (req, res, next) => {
try {
const entityName = req.query.name;
let entity = await getEntityWithDependencies($db, entityName);
const dependencies = {}
if (entity.dependencies) {
entity.dependencies.forEach(dependency => {
dependencies[dependency.name] = dependency;
});
delete entity.dependencies;
}
if (entity.dependency) entity = mapDependency(entity, dependencies)
return res.status(200).json({
success: true,
data: entity
});
} catch (error) {
return next(error)
}
}
}
const mapDependency = (entity, dependencies) => {
entity['dependency'] = dependencies[entity['dependency']];
if (entity['dependency'].dependency)
entity['dependency'] = mapDependency(entity['dependency'], dependencies)
return entity
}
const getEntityWithDependencies = async ($db, name) => {
const aggregationPipeline = [
{
$match: { name }
},
{
$graphLookup: {
from: 'entities',
startWith: '$dependency',
connectFromField: 'dependency',
connectToField: 'name',
as: 'dependencies',
}
}
];
const result = await $db.models.Entity.aggregate(aggregationPipeline).exec();
return result.length > 0 ? result[0] : null;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With