Mongoose:使用自上而下

时间:2016-10-02 09:15:51

标签: node.js mongoose tree promise bluebird

正如我所说in another question,我正在开展一个涉及树的项目。

  • 树使用父引用,因此每个节点都具有其父
  • 的id
  • 我需要从db自上而下(从root到child)加载树,并用children数组替换父引用(因为客户端需要它们)
  • 我选择了这种方法,因为我估计98%的操作要在节点上创建/更新(这样我只需要在更新时创建1个节点,而不是更新父节点以将子节点添加到节点数组)只有大约2%的读取操作(我只需读取完整的树,没有用于读取部分或子树的用例)

树模型是:

const mongoose = require("mongoose");
const Promise = require("bluebird");
mongoose.Promise = Promise;
const Node = require("./node-model");

const TreeSchema = new mongoose.Schema({
  root: { type: Schema.Types.ObjectId, ref: 'Node' },
});

节点模型:

const mongoose = require("mongoose");
const Promise = require("bluebird");
mongoose.Promise = Promise;

const NodeSchema = new mongoose.Schema({
  parent:  Schema.Types.ObjectId,
  children: [], // to be populated on loading the tree
  data: {
    d1: String, 
    //...
  }
});

NodeSchema.methods.populateTree = function() {
  return this.constructor.find({ parent: this._id }).exec()
    .then(function(arrayOfChildren) {
      return Promise.each(arrayOfChildren, function(child){
        this.children.push(child); // PROBLEM: 'this' is undfined here!
        delete child.parent; // delete parent reference because JSON has problems with circular references
        return child.populateTree();
      });
    });
}

此外,还有一个树容器:

const TreeContainerSchema = new mongoose.Schema({
  owner: { type: Schema.Types.ObjectId, ref: 'User', required: true },
  tree: { type: Schema.Types.ObjectId, ref: 'Tree' },
});

我正在尝试加载完整的树(在他的容器中)以JSON的形式将其发送回客户端,如下所示:

getTreeContainerById = function(req, res) {
  var promise = TreeContainer.
    findById(req.params.id).
    populate("owner", "name"). // only include name
    populate({
      path: "tree",
      populate: {
        path: "root",
        populate: "data"
      }
    }).exec();

    promise.then(function(treeContainer){
      return treeContainer.tree.root.populateTree()
        .then(function(){ return treeContainer });
    }).then(function(treeContainer) {
      // I need the tree container here to send it back to the client
      res.json(treeContainer);
    });
};

但是这种实施方式无效。我面临的问题是:

  • populateTree架构方法中,我无法通过“this”访问当前节点(未定义)但我需要以某种方式将引用添加到数组中
  • 如果我尝试使用child.parent.children.push,这也不起作用,因为我只有父(在child.parent中)的id而不是实体(我不认为它是从数据库中再次加载它的正确方法)
  • 在早期版本中,我遇到了问题,即在完全填充树之前将JSON发送回客户端,但我认为我通过使用模式方法解决了这个问题
  • 一般来说,我不知道,如果这是解决我的问题的正确方法(填充子引用并删除我树中的父引用)或者是否有更合适的解决方案

我希望,我可以清楚地解决问题。非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

populateTree如下所示:

NodeSchema.methods.populateTree = function() {
  var node = this;
  return this.constructor.find({ parent: this._id }).exec()
    .then(function(arrayOfChildren) {
      return Promise.each(arrayOfChildren, function(child){
        node.children.push(child);
        child.parent = null;
        return child.populateTree();
      });
    });
}

感谢@danh提出了相同意见!