问题
I'm having a problem saving items running through for loop if I attach any extra validation methods. Basically, I'm building an instagram API app that allows editors to remove photos that are unseemly. Photos are pulled from Instagram in batches of 20 and displayed to editors. If an editor clicks a photo, it is first put on a 'blacklist' database by ID, then deleted from the main photo database.
In order to not have blacklisted photos reappear on the feed, before saving an item to the main photo database, it needs to check the Instagram ID of the photo against the blacklist. To do this, I'm using a Schema method.
The problem right now, is that I'm only getting ONE photo saved to the DB. If I take out the method check, then I get all 20.
Here's my main create controller:
exports.create = function(req, res) {
var topic = req.body.topic || 'nyc';
var path = 'https://api.instagram.com/v1/tags/' + topic + '/media/recent?client_id=' + 'XXXXXXXXXX';
request.get({url: path}, function(err, response){
if (err){
console.log('Failed to get data: ', err);
return res.status(400).json({error: 'Not allowed'});
}
else{
// ------------------------------------------------
// Make sure we have JSON
//
var body = JSON.parse(response.body);
// ------------------------------------------------
// Loop through each response
//
for (var i = 0; i < body.data.length; i++ ){
var photoData = body.data[i];
// ------------------------------------------------
// If there is no caption, skip it
//
if (!photoData.caption){
text = '';
}
else{
text = photoData.caption;
}
// ------------------------------------------------
// Create new photo object
//
var photo = new Photo({
link: photoData.link,
username: photoData.user.username,
profilePicture: photoData.user.profile_picture,
imageThumbnail: photoData.images.thumbnail.url,
imageFullsize: photoData.images.standard_resolution.url,
caption: text,
userId: photoData.user.id,
date: photoData.created_time,
_id: photoData.id
});
photo.checkBlacklist(function(err, blacklist){
if (!blacklist){
photo.save(function(err, item){
if (err){
console.log(err);
}
console.log('Saved', item);
})
}
});
// -------------------------------------------------
//
// Save
//
// -------------------------------------------------
} // END FOR LOOP
console.log('Photos saved');
return res.json(201, {msg: 'Photos updated'} );
}
});
};
And here's my Schema for photos:
'use strict';
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
var Blacklist = require('../blacklist/blacklist.model');
var PhotoSchema = new Schema({
created: {type: Date, default: Date.now()},
date: String,
link: String,
username: String,
profilePicture: String,
imageThumbnail: {type: String, unique: true},
imageFullsize: String,
caption: String,
userId: String,
_id: {type: String, unique: true}
});
PhotoSchema.methods.checkBlacklist = function(callback){
return Blacklist.findById(this._id, callback);
};
module.exports = mongoose.model('Photo', PhotoSchema);
Strangely, I'm getting console messages for all 20 saves in the create controller: console.log('Saved', item);
But only ONE photo is actually saved. Any ideas why?
Thanks
回答1:
When you have to perform the same asynchronous task for items in an array, don't use a regular for loop. Check out async.each, it fits better in your scenario, like (just the else
part of your code):
var body = JSON.parse(response.body);
async.each(body.data, function (photoData, callback) {
// ------------------------------------------------
// If there is no caption, skip it
//
if (!photoData.caption){
text = '';
}
else{
text = photoData.caption;
}
// ------------------------------------------------
// Create new photo object
//
var photo = new Photo({
link: photoData.link,
username: photoData.user.username,
profilePicture: photoData.user.profile_picture,
imageThumbnail: photoData.images.thumbnail.url,
imageFullsize: photoData.images.standard_resolution.url,
caption: text,
userId: photoData.user.id,
date: photoData.created_time,
_id: photoData.id
});
photo.checkBlacklist(function(err, blacklist){
if (!blacklist){
photo.save(function(err, item){
if (err){
console.log(err);
}
console.log('Saved', item);
callback();
});
}
});
}, function (error) {
if (error) res.json(500, {error: error});
console.log('Photos saved');
return res.json(201, {msg: 'Photos updated'} );
});
Don't forget to install
npm install async
and require async
:
var async = require('async');
回答2:
How about solving it recursively
saveGames = (depth) => {
if (depth > 0) {
var newGame = new Game({ user: user._id });
newGame.save((err, game) => {
if (err) {
console.log(err);
return res.status(203).json({
title: 'error',
error: { message: 'Error Saving Games' }
});
}
user.games.push(game);
user.save((err, user) => {
if (err) {
console.log(err);
return res.status(203).json({
title: 'error',
error: { message: 'Error Saving Games' }
});
}
saveGames(depth - 1);
});
});
}
}
saveGames(5);
来源:https://stackoverflow.com/questions/28478606/saving-items-in-mongoose-for-loop-with-schema-methods