在数据库问题中坚持数据,在控制台上接收NULL

我是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; } 

我一直在debugging这个前端部分,一切似乎都OK …

现在后退:

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打印在terminal,但如果我做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); } }); } }); }); } 

那么你认为我的问题在这里呢? 我究竟做错了什么 ?

我是这样做的,我会从头到尾传授

从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()这是每次用户再次login的方法。

我没有任何删除方法,因为我们没有删除任何东西,我们只是在观察声明的变化。

另外我正在使用Redis服务器

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

 'use strict'; module.exports = { connection: 'RedisServer', attributes: { sport: { type: 'array', required: false }, user: { type: 'string', required: true } } }; 

另外,在config文件夹中我们有policies.js ,我不能告诉你如何处理这个,因为是你的configuration,但我的是:

  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

这里是我发表的post,看看

  .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(); } }); 

所以,这是最终的版本,如果这个长期的项目,你不得不触摸很多文件来获得这个,保存/坚持数据库中的数据,所以,看到这个代码,因为这是我到目前为止,正在工作很好,而且速度很快,我还没有任何错误,离开这里,问你需要知道的问题,白天我会回答。 希望这可以帮助

如果您正在使用mongooseJS (看起来您是)并且该服务的目的是将该运动添加到体育arrays,那么您可以使用findOneAndUpdate方法(这将使用exec方法返回一个promise)并显着减less服务至:

 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 } }; 

我认为这可以做得更简单 – 而不是像这样更新,只需跟踪客户端的所有checkbox,并在更改时更新整个事件。

我想你错过了一些angular色可以很容易地为你做的事情,在这种情况下,你可以在客户端而不是服务器上closures所有的工作负载。

首先,让你的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会为你创build一个运动对象,跟踪什么或者没有被检查。 而不是试图在数据库内部pipe理它,只要让angular色照顾它,每当它改变时,覆盖整个logging。

您可以在checkbox中使用切换function:

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

在后端,你可以做类似的build议在其他答案:

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

这样你就可以less用代码,阅读起来更容易,而且你可以从服务器中删除大量的逻辑。

除非有缺失的原因,否则你不需要在你的ajax调用中使用$ q。 你可以使用$ httpbuild立成功和错误来处理承诺。

你需要改变你的模型,而不是一个数组。

此外,如果您实际上使用风帆,只需使用蓝图PUT。 您甚至不需要任何逻辑 – 当您生成api时,sails已经生成了它。

当你加载你的页面时,只需将logging返回,并将data.sport推入到$ scope.sport中,并且checkbox应该更新。