Конвертируйте плоские данные в иерархию mongodb, используя Mongoose

Я создал модель, которая имеет следующие свойства:

  1. Я бы
  2. дети
  3. родитель

Если для родителя задано значение NULL, документ будет считаться родителем верхнего уровня. Каждый документ может иметь или не иметь список дочерних элементов, который просто содержит идентификаторы другого документа.

db.categories.insert( { _id: "MongoDB", children: [],name: '', parent: 'Databases'} )
db.categories.insert( { _id: "dbm", children: [], parent: 'Databases' } )
db.categories.insert( { _id: "Databases", children: [ "MongoDB", "dbm" ], parent: 'Programming' } )
db.categories.insert( { _id: "Languages", children: [], parent: 'Programming' } )
db.categories.insert( { _id: "Programming", children: [ "Databases", "Languages" ],parent: 'books' } )
db.categories.insert( { _id: "Books", children: [ "Programming" ],parent: null } )

Из приведенной выше модели мне нужно создать вывод, как это:

{
    name: "books",
    nodes: [
        {
            name: "Programming",
            nodes: [
                {
                    name: "Databases",
                    nodes: [
                        {
                            name: "MonogoDB"
                        },
                        {
                            name: "dbm"
                        }
                    ]
                },
                {
                    name: "Languages"
                }
            ]
        }
    ]
}

До сих пор я пробовал это, но из-за асинхронного характера findByID(), я не получаю желаемого результата. Пожалуйста, предложите изменения.

myDoc.find({
    parent: null
  }, function (err, topics) {
    if (err) {
      return handleError(res, err);
    }
    var docTree = [];
    _.each(document, function(parentDoc) {
       var doc = {};
       doc.text = parentDoc.name;
      doc.nodes = [];
      _.each(parentDoc.children, function(child) {
        doc.nodes.push(processChildren(child));
      });
      docTree.push(doc);

    });



function processChildren(child) {

  myDoc.findById(child, function (err,item) {
    var doc = {};
    doc.name = item._doc.name;
    doc.nodes = [];
    if (item._doc.children === null) {
      return topic;
    } else {
      _.each(item._doc.children, function (chld) {
        processChildren(chld);
      });
    }
    return doc;
  });

};

1 ответ

Вы можете попробовать позвонить lean() метод после find() метод, поскольку документы, возвращаемые по запросам с включенной опцией lean, являются обычными объектами JavaScript. Затем вы можете манипулировать этими объектами, чтобы получить желаемую иерархическую структуру. Следующее может не дать желаемого результата, но подтолкнет вас в правильном направлении:

Model.find({}).lean().exec(function (err, docs) {
    if (err) {
      return handleError(res, err);
    }
    var i, len, temp, top_level, id, parent, hierarchical, nodePendingObj, doc, _id, _parent, _children;
    i = 0;
    top_level = [];
    temp = {};
    obj = {};
    nodePendingObj = {};
    _id = '_id';
    _parent = 'parent';
    _children = 'children';

    _.each(docs, function(doc) {
        id = doc['_id'];
        parent = doc[_parent];
        temp[id] = doc;
        if (parent === undefined || parent === null) {      
            obj["name"] = id;
            obj["nodes"] = doc[_children];
            top_level.push(obj);
        } 
        else {
            if (temp[parent] !== undefined) {           
                if (temp[parent][_children] === undefined) {
                    temp[parent][_children] = [];
                }
                var o = {};
                o["name"] = id;
                if (doc[_children].length !== 0) o["nodes"] = doc[_children];
                temp[parent][_children].push(o);
            } else {            
                if (nodePendingObj[parent] === undefined) {
                    nodePendingObj[parent] = [];
                }
                var o = {};
                o["name"] = id;
                if (doc[_children].length !== 0) o["nodes"] = doc[_children];
                nodePendingObj[parent].push(o);             
            }    
            delete doc[_parent];
        }

        if (nodePendingObj[id] !== undefined) {     

            var len = nodePendingObj[id].length;
            if (doc[_children] === undefined) {
                doc[_children] = [];
            }
            while (len-- > 0) {
                doc[_children].push(nodePendingObj[id].shift());
            }
        }
    });

    if (top_level.length === 1) {
        hierarchical = top_level[0];
    } else if (top_level.length > 1) {
        hierarchical = {};
        hierarchical[_children] = top_level;
    } else {
        hierarchical = {};
    }
    console.log(JSON.stringify(hierarchical));
});

Проверьте демо ниже.

var documents = [
 {
  "_id" : "MongoDB",
  "children" : [],
  "name" : "",
  "parent" : "Databases"
 },{
  "_id" : "dbm",
  "children" : [],
  "parent" : "Databases"
 },{
  "_id" : "Databases",
  "children" : [ 
   "MongoDB", 
   "dbm"
  ],
  "parent" : "Programming"
 },{
  "_id" : "Languages",
  "children" : [],
  "parent" : "Programming"
 },{
  "_id" : "Programming",
  "children" : [ 
   "Databases", 
   "Languages"
  ],
  "parent" : "books"
 },{
  "_id" : "books",
  "children" : [ 
   "Programming"
  ],
  "parent" : null
 }
];
var i, len, temp, top_level, id, parent, hierarchical, nodePendingObj, doc, _id, _parent, _children;
i = 0;
top_level = [];
temp = {};
obj = {};
nodePendingObj = {};
_id = '_id';
_parent = 'parent';
_children = 'children';


_.each(documents, function(doc) { 
 id = doc['_id'];
 parent = doc[_parent];
 temp[id] = doc;
 if (parent === undefined || parent === null) {  
  obj["name"] = id;
  obj["nodes"] = doc[_children];
  top_level.push(obj);
 } 
 else {
  if (temp[parent] !== undefined) {   
   if (temp[parent][_children] === undefined) {
    temp[parent][_children] = [];
   }
   var o = {};
   o["name"] = id;
   if (doc[_children].length !== 0) o["nodes"] = doc[_children];
   temp[parent][_children].push(o);
  } else {   
   if (nodePendingObj[parent] === undefined) {
    nodePendingObj[parent] = [];
   }
   var o = {};
   o["name"] = id;
   if (doc[_children].length !== 0) o["nodes"] = doc[_children];
   nodePendingObj[parent].push(o);
   
  }    
  delete doc[_parent];
 }
 
 if (nodePendingObj[id] !== undefined) {  
  
  var len = nodePendingObj[id].length;
  if (doc[_children] === undefined) {
   doc[_children] = [];
  }
  while (len-- > 0) {
   doc[_children].push(nodePendingObj[id].shift());
  }
 }
});

if (top_level.length === 1) {
 hierarchical = top_level[0];
} else if (top_level.length > 1) {
 hierarchical = {};
 hierarchical[_children] = top_level;
} else {
 hierarchical = {};
}

pre.innerHTML = JSON.stringify(hierarchical, null, 4);
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<pre id="pre"></pre>

Другие вопросы по тегам