【问题标题】:Sails.js: one-to-many relationship for a model itselfSails.js:模型本身的一对多关系
【发布时间】:2014-12-26 22:43:41
【问题描述】:

我正在尝试使用 Sails.js 和 MongoDB 构建一个支持多级类别的简单应用程序。一个类别可以有许多子类别。因此,在我的Category 模型中,我在其自身类别中设置了一对多关系:

module.exports = {

  adapter: 'mongo',

  attributes: {
    categoryTitle: {
      type: 'string',
      required: true
    },

//owner or parent of the one-to-many relationship
parentCat: {
  model: 'category'
},

//sub categories
subCategories: {
  collection: 'category',
  via: 'parentCat'
},
  }};

使用 AngularJS 中的 ng-repeat 指令将类别显示在选择下拉列表中,例如

<select class="selector3" id="categoryParent" ng-model="category.parent">
                <option>Choose a category or none</option>
                <option ng-repeat="cat in categories" value="{{cat.categoryTitle}}">{{cat.categoryTitle}}</option>
            </select>

AngularJS CategoryController 中,我使用$scope.category.parent 来捕获所选类别(作为父类别)的值。这一步有效,因为我可以看到console.log($scope.category.parent); 选择的值。

但是,当我将新类别及其父类别一起保存到 MongoDB 时,即使其他字段保存正确,父类别仍为空,如 Mongo 终端所示。 我想问题出在我为在 Sails 中保存新类别而编写的“创建”API 上。您能找出以下代码中可能出错的地方吗?

create: function(req, res, next) {
var params = req.allParams();

// set parent category if exists
if (params.parentCat) {

    var parentCategory = Category.findOne({categoryTitle : params.parentCat})
        .exec(function(err, category) {
        if (err) {
            return null; //not found
        }

        return category; //found, return the category
    });

    params.parentCat = parentCategory;  //set the parent category in params
}

//insert the new category to MongoDB
Category.create(params, function(err, category) {
    if (err) {
        console.log('category addition failed');
        return next(err);
    }
    console.log('successfully added the category: ' + category.categoryTitle);
    res.redirect('/category');
});

} //create

【问题讨论】:

    标签: javascript angularjs node.js mongodb sails.js


    【解决方案1】:

    您在这里混淆了一些概念。

    首先

    var parentCategory = Category.findOne({categoryTitle : params.parentCat})
    

    请注意,水线方法 findOne 不会从数据库中返回文档。因此,上述陈述不会为您服务您打算达到的目的。重要的是您在 exec 函数中提供的回调函数。可以这样想:

    Node.js 事件循环将只执行 Category.findOne 并继续执行下一条语句,而无需等待 findOne 完成。这里的下一条语句是:

    params.parentCat = parentCategory
    

    请注意,从 MongoDB 获取尚未完成。即使完成了,findOne 也不会像我上面所说的那样返回对数据库中文档的引用。所以,这不是在 Node.js 中做事的方式。相反,如果你想访问数据库对象,它存在于exec中回调函数的category变量中。

    现在第二个问题是下面的语句

    return category;
    

    如您所知,return 将使您完全摆脱创建操作。此外,这里要注意的一个有趣的点是,该语句与底部的重定向语句之间存在竞争。这就是为什么

    Node.js 事件循环执行它遇到的每个语句。如果语句是阻塞语句(如var x = &lt;some computation without callback function&gt;),那么它将停留在该语句并等待其完成。否则,如果该语句是带有回调函数的异步语句(如Category.findOne({}).exec(function (err, category){})),则事件循环将移至下一条语句,并在 findOne 完成时执行回调。

    现在,在这种情况下,findOne 将被执行,事件循环将继续进行

    params.parentCat = parentCategory; 
    

    这不是异步语句,但它会立即完成,并且事件循环会继续进行

    Category.create()
    

    现在,您可以认为 findOne 和 create 将在 mongoDB 中并行执行。一旦他们的数据库操作完成,回调函数将被执行。无论哪个回调先执行,都会执行其返回语句。所以,这里的行为是不可预测的。 return category 可能会执行或res.redirect('/category'); 可能会执行。

    我已经重写了下面的创建函数,保留了上面提到的所有要点

    create: function(req, res, next) {
        var params = req.params.all();
    
        // set parent category if exists
        if (params.parentCat) {
            Category.findOne({categoryTitle : params.parentCat}).exec(function (err, parentCategory) {
                if (err) {
                    return res.json(500, 'Sever error'); //not found
                }
                else{
                    params.parentCat = parentCategory.id;  //set the parent category in params
                    //insert the new category to MongoDB
                    Category.create(params, function (err, category) {
                        if (err) {
                            console.log('category addition failed');
                            return next(err);
                        }
                        console.log('successfully added the category: ' + category.categoryTitle);
                        res.redirect('/category');
                    });                     
                }
            });
        }
        else{
            return res.json(500,'Server error. Parent category required'); 
        }
    }
    

    【讨论】:

    • 哇,非常感谢您的详细回复,不胜感激。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    • 2015-06-27
    • 2014-02-02
    • 2016-01-11
    • 2013-11-20
    • 1970-01-01
    相关资源
    最近更新 更多