Save data in DB problem by getting NULL on console

I am new to NodeJS, and I had a problem trying to save / save some data in the database.

start from the beginning so you can understand more easily. I have a list of sports with the ability to check or uncheck what I need to save what is checked.

FRONT END:

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

I debugged this front end and everything seems OK ...

Now BACK END:

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 (model)

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

in this part, I see how this console prints in the terminal, but if I do console.log(sportChecked) or console.log(newSport) , all I get is an array that says null everywhere ...

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

So what do you think my problem is here? what am I doing wrong?

+6
source share
3 answers

that's how i did it, i will teach how from start to finish

starting from the Node.js part, I use Sails.js and 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'}); } } }; 

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

as you can see here, we have only 2 methods, the first

sportChecked() is the one that fires when the user checks or deselects any of the elements.

and then we have getSportChecked() , which is a method called every time the user logs in again.

I don’t have a deletion method, because we don’t delete anything, we just watch the instruction change.

I also work with a Redis server

Remember to create a model, I gave'em the name SportSelection.js

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

In addition, there is policy.js in the config folder, I can not tell you how to work with this, because this is your configuration, but mine:

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

then go to the Front End Part (remember: AngularJS)

I have a controller, 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(); }); }; 

which works according to this template

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

then service.js

know AngularJS

that's where i make a message and get watch

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

first focus on setSportChecked() and getSportChecked() , where the magic happens in this service, then the getSports() function calls getSportChecked() , which looks like this

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

So, this is the final version, if this is a long project, you need to touch a large number of files to get with it, save / transfer data to the database, so see this code, because I still work fine with it and quickly, I don’t have any errors so far, looking up from here, ask the questions you need to know, I will answer during the day. Hope this helps

+3
source

IF you use mongooseJS (as you can see) And the purpose of the service is to add sport to the sports array, then you can use the findOneAndUpdate method (which will return the promise with the exec method) and significantly reduce the level of service to:

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

$addToSet will only add a value if it is not already in the array. If duplicates are acceptable, you can use $push

As stated in the comments, you are probably using the waterline. If so, the update method seems to behave similarly to findOneAndUpdate . Maybe this might work (I did not check if you need to call exec or not):

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

I think this can be done much easier - instead of updating it like this, just keep track of all your checkboxes on the client side and update everything when it changes.

I think that you have missed some things that angular can do for you very easily, in which case you can disconnect the entire workload on the client, and not on the server.

First, make your HTML code something like this:

 <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 will create for you a sports object that will track everything that is or is not checked. Instead of trying to manage this in the database, just angular will take care of it, and whenever it changes, overwrite the entire record.

You can use your switch function in the ng change of your checkboxes:

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

On the backend, you can do the same as in the other answers:

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

This way you have less code, it is easier to read, and you remove the LOT of logic from the server.

If for some reason I am missing, you do not need to use $ q in your ajax call. You can simply use the $ http built-in success and error to handle promises.

You will need to change your model, by the way, to store a sports facility, not an array.

Also, if you are actually using sails, just use PUT. You don't even need logic - sails already generated it when you create your api.

When you load your page, just return the entry and click data.sport in $ scope.sport and your checkboxes should update.

+1
source

Source: https://habr.com/ru/post/983437/


All Articles