MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

population récursive de mangouste

vous pouvez le faire maintenant (avec https://www.mongodb.com/blog/post/introducing-version-40-mongoose-nodejs-odm)

var mongoose = require('mongoose');
// mongoose.Promise = require('bluebird'); // it should work with native Promise
mongoose.connect('mongodb://......');

var NodeSchema = new mongoose.Schema({
    children: [{type: mongoose.Schema.Types.ObjectId, ref: 'Node'}],
    name: String
});

var autoPopulateChildren = function(next) {
    this.populate('children');
    next();
};

NodeSchema
.pre('findOne', autoPopulateChildren)
.pre('find', autoPopulateChildren)

var Node = mongoose.model('Node', NodeSchema)
var root=new Node({name:'1'})
var header=new Node({name:'2'})
var main=new Node({name:'3'})
var foo=new Node({name:'foo'})
var bar=new Node({name:'bar'})
root.children=[header, main]
main.children=[foo, bar]

Node.remove({})
.then(Promise.all([foo, bar, header, main, root].map(p=>p.save())))
.then(_=>Node.findOne({name:'1'}))
.then(r=>console.log(r.children[1].children[0].name)) // foo

alternative simple, sans Mangouste :

function upsert(coll, o){ // takes object returns ids inserted
    if (o.children){
        return Promise.all(o.children.map(i=>upsert(coll,i)))
            .then(children=>Object.assign(o, {children})) // replace the objects children by their mongo ids
            .then(o=>coll.insertOne(o))
            .then(r=>r.insertedId);
    } else {
        return coll.insertOne(o)
            .then(r=>r.insertedId);
    }
}

var root = {
    name: '1',
    children: [
        {
            name: '2'
        },
        {
            name: '3',
            children: [
                {
                    name: 'foo'
                },
                {
                    name: 'bar'
                }
            ]
        }
    ]
}
upsert(mycoll, root)


const populateChildren = (coll, _id) => // takes a collection and a document id and returns this document fully nested with its children
  coll.findOne({_id})
    .then(function(o){
      if (!o.children) return o;
      return Promise.all(o.children.map(i=>populateChildren(coll,i)))
        .then(children=>Object.assign(o, {children}))
    });


const populateParents = (coll, _id) => // takes a collection and a document id and returns this document fully nested with its parents, that's more what OP wanted
  coll.findOne({_id})
    .then(function(o){
      if (!o.parent) return o;
      return populateParents(coll, o.parent))) // o.parent should be an id
        .then(parent => Object.assign(o, {parent})) // replace that id with the document
    });