我是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);
}
});
}
});
});
}
那你觉得我的问题在这里怎么样?我做错了什么?
答案 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>
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,并且您的复选框应该更新。