在数据库问题中保留数据,在控制台上接收NULL

时间:2015-03-06 17:54:27

标签: javascript angularjs node.js sails.js

我是NodeJS的新手,我在尝试在数据库中保留/保存一些数据时遇到问题。

让我们从头开始,让您更容易理解。我有一个运动列表,可选择选中或取消选中,这是我需要保留的,经过检查的。

前端:

controller.js

$scope.toggleSportSelection = function(sport) {
  var params = {};
  params.user = $scope.customer.customer;
  sport.checked = !sport.checked;
  SportsFactory.setSportChecked(params);
};

service.js

  setSportChecked: function(params) {
    var defer = $q.defer();
    $http.post(CONSTANT_VARS.BACKEND_URL + '/sports/checked', params)
    .success(function(sportChecked) {
        LocalForageFactory.remove(CONSTANT_VARS.LOCALFORAGE_SPORTS_CHECKED, params);
        defer.resolve(sportChecked);
      })
      .error(function(err) {
        console.log(err);
        defer.reject(err);
      });
    return defer.promise;
  }

我一直在调试这个前端部分,一切似乎都没问题......

现在回到结束:

setSportCtrl.js

module.exports = {

  setCheck: function(req, res) {
    var checkedSportParams = req.body;

    SportSelectionService.sportChecked(checkedSportParams).then(function() {
      res.json(200, {msg: 'OK'});
    }, function(err) {
      res.json(400, err);
    });
  }
}

SportSelection.js (型号)

module.exports = {
  connection: 'RedisServer',
  attributes: {
    sport: {
      type: 'array',
      required: false
    },

    user: {
      type: 'string',
      required: true
    }
  }
};

在这部分中,我可以看到终端中如何打印console,但如果我console.log(sportChecked)console.log(newSport)我得到的是一个数组,其中显示null无处不在...

SportSelectionService.js

module.exports = {

  sportChecked: function(params) {
    var Promise = require('bluebird');
    return new Promise(function(fullfill, reject) {
      console.time('sportChecked_findOne');
      SportSelection.findOne({
        user: params.user
      }).exec(function(err, sportChecked) {
        console.timeEnd('sportChecked_findOne');
        var newSport;
        if (err) {
          reject(new Error('Error finding user'));
          console.error(err);
        }else if (sportChecked) {
          newSport =  sportChecked.sport;
          console.time('sportChecked_update');
          SportSelection.update({
            user: params.user
          },
          {
            sport: newSport
          }).exec(function(err, sportCheckedUpdated) {
            console.timeEnd('sportChecked_update');
            if (err) {
              reject(new Error('Error on sportChecked'));
            }else {
              fullfill(sportCheckedUpdated);
            }
          });
          if (sportChecked.sport) {
            sportChecked.sport.push(params.sport);
            console.log('New sport added');
          }else {
            sportChecked.sport = [params.sport];
          }
        }else {
          console.time('sportChecked_create');
          SportSelection.create({
            sport: [params.sport],
            user: params.user
          }).exec(function(err, created) {
              console.timeEnd('sportChecked_create');
              if (err) {
                reject(new Error('Error on sportChecked'));
              }else {
                fullfill(created);
              }
            });
        }
      });
    });
  }

那你觉得我的问题在这里怎么样?我做错了什么?

3 个答案:

答案 0 :(得分:3)

这是我做的方式,我将教导从开始到结束的方式

从Node.js部分开始,我使用的是Sails.js和lodash

<强> SetSportsController.js

'use strict';

module.exports = {

  setCheck: function(req, res) {
    var checkedSportParams = req.body;
    SportSelectionService.sportChecked(checkedSportParams).then(function() {
      res.json(200, {msg: 'OK'});
    }, function(err) {
      res.json(400, err);
    });
  },

  retrieveSetCheck: function(req, res) {
    if (req.params) {
      SportSelectionService.getSportChecked(req.params).then(function(sportChecked) {
        res.json(200, sportChecked);
      }, function(err) {
        res.json(400, err);
      });
    }else {
      res.json(400, {error: 'Error retrieving Sports'});
    }
  }
};

比我们选择 SportSelectionService.js

'use strict';

var _ = require('lodash');

module.exports = {

  sportChecked: function(params) {
    var Promise = require('bluebird');
    return new Promise(function(fullfill, reject) {
      SportSelection.findOne({
        user: params.user
      }).exec(function(err, sportChecked) {//this array comes with duplicates
        var newSport,
            sportCheckedUniq = _.uniq(sportChecked.sport);//prevents duplicates
        if (err) {
          reject(new Error('Error finding user'));
          console.error(err);
        }else if (sportChecked) {
          newSport = sportCheckedUniq || [];
          if (_.includes(sportCheckedUniq, params.sport)) {
            sportCheckedUniq = _.pull(newSport, params.sport);
            sportCheckedUniq = _.difference(newSport, params.sport);
          }else {
            newSport.push(params.sport);
            sportCheckedUniq = newSport;
          }
          SportSelection.update({
            user: params.user
          },
          {
            sport: newSport
          }).exec(function(err, sportCheckedUpdated) {
            if (err) {
              reject(new Error('Error on sportChecked'));
            }else {
              fullfill(sportCheckedUpdated);
            }
          });
          if (sportCheckedUniq) {
            sportCheckedUniq.push(params.sport);
          }else {
            sportCheckedUniq = [params.sport];
          }
        }else {
          SportSelection.create({
            sport: [params.sport],
            user: params.user
          }).exec(function(err, created) {
              if (err) {
                reject(new Error('Error on sportChecked'));
              }else {
                fullfill(created);
              }
            });
        }
      });
    });
  },

  getSportChecked: function(params) {
    var Promise = require('bluebird');
    return new Promise(function(fullfill, reject) {
      console.time('sportChecked_findOne');
      SportSelection.findOne({
        user: params.user
      }).exec(function(err, sportChecked) {
        console.timeEnd('sportChecked_findOne');
        if (err) {
          reject(new Error('Error finding sportChecked'));
          console.error(err);
        }else {
          if (sportChecked) {
            fullfill(sportChecked);
          }else {
            SportSelection.create({
              // 10 is the ID for soccer, which must unchecked by default on every single user.
              sport: [10],
              user: params.user
            }).exec(function(err, created) {
              console.log(err);
              console.log(created);
              if (err) {
                reject(new Error('Error on sportChecked'));
              }else {
                fullfill(created);
              }
            });
          }
        }
      });
    });
  }
};

正如你在这里看到的,我们只有两种方法,第一种

sportChecked()是用户选中或取消选中任何项目时触发的内容。

然后我们有getSportChecked()这是每次用户再次登录时调用的方法。

我没有任何删除方法,因为我们没有删除任何内容,我们只是在观察更改语句。

我也在使用Redis服务器

不要忘记创建模型,我给了一个名字 SportSelection.js

'use strict';

module.exports = {
  connection: 'RedisServer',
  attributes: {
    sport: {
      type: 'array',
      required: false
    },

    user: {
      type: 'string',
      required: true
    }
  }
};

另外,在配置文件夹中我们有 policies.js ,我无法告诉您如何使用它,因为是您的配置,但我的是:

  SetSportsController: {
    setCheck: ['jwtAuth', 'sanitizerPolicy', 'headersPolicy'],
    retrieveSetCheck: ['jwtAuth', 'sanitizerPolicy']
  },...

然后,我们转到前端部分(记住:AngularJS)

我有一个控制器 controller.js

$scope.toggleSportSelection = function(sport) {
  SportsFactory.setSportChecked({
    user: $scope.customer.customer,
    sport: sport.id
  }).then(function() {
    sport.checked = !sport.checked;
    $ionicScrollDelegate.resize();
  }, function() {
    $ionicScrollDelegate.resize();
  });
};

正在使用此模板

  <ion-item ng-repeat="sport in sportsFilter track by $index"
            ng-click="toggleSportSelection(sport)">
    {{:: sport.name}}
  </ion-item>

然后, service.js

了解AngularJS

这是我发帖的地方,看看

  .factory('SportsFactory', function($http, $q, AuthFactory, LocalForageFactory,
                                     LeaguesFactory, ImageFactory, CONSTANT_VARS) {

  getSports: function(customer) {
    var defer = $q.defer(),
    _this = this;

    LocalForageFactory.retrieve(CONSTANT_VARS.LOCALFORAGE_SPORTS)
      .then(function(sports) {
        if (!_.isNull(sports)) {
          defer.resolve(sports);
        }else {
          $http.get(CONSTANT_VARS.BACKEND_URL + '/lines/sports/' + customer.agent)
            .success(function(sports) {
              sports = _.sortBy(sports, function(sport) {
                return sport.priority;
              });
              _this.getSportChecked(customer).then(function(sportChecked) {
                var sportIds = _.pluck(sports, 'id'),
                    intersectedSports = _.intersection(sportIds, sportChecked.sport);
                if (sports.length) {
                  sports = _.map(sports, function(sport) {
                    sport.checked = !_.includes(intersectedSports, sport.id);
                    return sport;
                  });
                }else {
                  AuthFactory.logout();
                }
              });
              _.each(sports, function(sport) {
                var sportImg = ImageFactory.sportImages(sport);
                if (sportImg.length) {
                  sport.img = sportImg[0];
                }else {
                  sport.img = 'https://placehold.it/40x40';
                }
              });
              defer.resolve(sports);
            })
          .error(function(err) {
            defer.reject(err);
          });
        }
      });
    return defer.promise;
  },

  setSportChecked: function(params) {
    var defer = $q.defer();
    $http.post(CONSTANT_VARS.BACKEND_URL + '/sports/checked', params)
    .success(function(sportChecked) {
        LocalForageFactory.remove(CONSTANT_VARS.LOCALFORAGE_SPORTS_CHECKED, params);
        defer.resolve(sportChecked);
      })
      .error(function(err) {
        console.log(err);
        defer.reject(err);
      });
    return defer.promise;
  },

  getSportChecked: function(customer) {
    var defer = $q.defer(),
        user,
        rejection = function(err) {
          defer.reject(err);
        };

    LocalForageFactory.retrieve(CONSTANT_VARS.LOCALFORAGE_SPORTS_CHECKED)
      .then(function(sportChecked) {
        user = customer.customer;
        if (!_.isNull(sportChecked)) {
          defer.resolve(sportChecked);
        }else {
          $http.get(CONSTANT_VARS.BACKEND_URL + '/sports/getChecked/' + user)
          .success(function(sportChecked) {
            LocalForageFactory.set(CONSTANT_VARS.LOCALFORAGE_SPORTS_CHECKED, sportChecked);
            defer.resolve(sportChecked);
          })
          .error(rejection);
        }
      }, rejection);
    return defer.promise;
  }
});

首先,将注意力集中在setSportChecked()getSportChecked()上,此服务中有魔术发生的地方,然后函数getSports()会调用getSportChecked()像这样

          _this.getSportChecked(customer).then(function(sportChecked) {
            var sportIds = _.pluck(sports, 'id'),
                intersectedSports = _.intersection(sportIds, sportChecked.sport);
            if (sports.length) {
              sports = _.map(sports, function(sport) {
                sport.checked = !_.includes(intersectedSports, sport.id);
                return sport;
              });
            }else {
              AuthFactory.logout();
            }
          });

所以,这是最终版本,如果这个长项目,你必须触摸大量的文件才能得到这个,在数据库中保存/保存数据,所以,看看这段代码,因为这是我到目前为止的方式并且工作得很好而且很快,我还没有错误,离开这里,问你需要知道的问题,我将在白天回答。希望这有帮助

答案 1 :(得分:1)

如果你正在使用mongooseJS(看起来你是)该服务的目的是将运动添加到运动阵列然后你可以使用findOneAndUpdate方法(将使用exec方法返回承诺)并将服务显着减少到:

module.exports = {
  sportChecked: function(params) {
    return SportSelection.findOneAndUpdate(
      {user: params.user},
      {$addToSet: {sports: params.sport}}
    ).exec();
  }
};

$addToSet只会添加值,如果它尚未存在于数组中。如果可以接受重复项,您可以使用$push

正如评论中指出的那样,你可能会使用水线。如果是这样,则update方法的行为与findOneAndUpdate类似。所以也许这可能有用(我没有检查你是否需要拨打exec):

module.exports = {
  sportChecked: function(params) {
    return SportSelection.update(
      {user: params.user},
      {$addToSet: {sports: params.sport}}
    ).exec(); // Not sure if this is necessary
  }
};

答案 2 :(得分:1)

我认为这可以更简单地完成 - 而不是像那样更新它,只需跟踪客户端的所有复选框,并在更改时更新整个事物。

我认为你错过了一些角度可以很容易为你做的事情,在这种情况下你可以在客户端而不是服务器上关闭所有的工作量。

首先,让你的HTML像这样:

<form name="myForm">
      Basketball <input type="checkbox" ng-change="updateRecord()" ng-model="sport.basketball"><br />
      Baseball <input type="checkbox" ng-change="updateRecord()" ng-model="sport.baseball"><br />
      Football <input type="checkbox" ng-change="updateRecord()" ng-model="sport.football"><br />
      Soccer <input type="checkbox" ng-change="updateRecord()" ng-model="sport.soccer"><br />
      Golf <input type="checkbox" ng-change="updateRecord()" ng-model="sport.golf"><br />
      <br />{{sport}}
      <br /><span ng-show="loading">Updating Redis</span>
    </form>

Plunker

Angular将为您创建一个运动物体,用于跟踪任何已检查或未检查的物体。不要试图在数据库中管理它,只需让角度处理它,并且每当它改变时,覆盖整个记录。

您可以在复选框的ng-change中使用切换功能:

$scope.toggleSportSelection = function(sport) {
  var params = {};
  params.user = $scope.customer.customer;
  params.sport = sport
  SportsFactory.setSportChecked(params);
};

在后端,您可以采用与其他答案中建议的相似的方式:

module.exports = {
  sportChecked: function(params) {
    return SportSelection.update(
      {user: params.user},
      {sports: params.sport}}
    ).exec(); 
  }
};

通过这种方式,您可以减少代码,更容易阅读,并从服务器中删除大量逻辑。

除非我缺少某些原因,否则您不需要在ajax调用中使用$ q。您可以使用成功和错误构建的$ http来处理承诺。

顺便说一句,您需要更改模型来保存运动物体而不是阵列。

另外,如果您实际上正在使用风帆,请使用蓝图PUT。你甚至不需要任何逻辑 - 当你生成api时,sails已经生成了它。

当您加载页面时,只需返回记录,然后将data.sport推送到$ scope.sport,并且您的复选框应该更新。