mongoose/MEAN.js - model.find() возвращает пустой массив, если он отфильтрован

я новичок в mean.js, так что это может быть просто неправильный синтаксис, но когда я использую model.find() с запросом внутри (option.find({poll_id:1}), он возвращает пустой массив.

опрос.сервер.модель.js

'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

/**
 * Poll Schema
 */
var PollSchema = new Schema({
    poll_id: {type:Number},
    user_id: {type:Number},
    poll_question: {type:String},
    poll_language: {type:String},
    poll_description: {type:String},
    poll_description_raw: {type:String},
    poll_weight_additional: {type:Number},
    poll_flag_active:{type:Number,default:1},
    poll_flag_18plus:{type:Number,default:0},
    poll_flag_expire:{type:Number,default:0},
    poll_flag_deleted:{type:Number,default:0},
    poll_flag_moderated:{type:Number,default:0},
    poll_flag_favourised:{type:Number,default:0},
    poll_date_expiration:{type:Date},
    poll_date_inserted:{type:Date,default:Date.now()},
    poll_flag_updated:{type:Date},
    show_thumbs:{type:Number},
    comments:{
        type: Schema.ObjectId,
        ref: 'User'
    }
});

mongoose.model('Poll', PollSchema);

option.server.model.js

'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

/**
 * Option Schema
 */
var OptionSchema = new Schema({
    option_id:{type:Number},
    poll_id:{type:Number},
    option:{type:Number}
});

mongoose.model('Option', OptionSchema);

опросы.server.controller.js

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
    errorHandler = require('./errors.server.controller'),
    Poll = mongoose.model('Poll'),
    Option = mongoose.model('Option'),
    _ = require('lodash');

/**
 * List of Polls
 */
exports.list = function(req, res) {
    Poll.find().limit(10).sort('_id')/*.populate('user', 'displayName')*/.exec(function(err, polls) {
        if (err) {

            return res.status(400).send({
                message: errorHandler.getErrorMessage(err)
            });

        } else {
            for (var i=0; i < polls.length; i++) {
                // this works, returns an array with 10 items
                Option.find().exec(function(err,docs){
                    console.log(docs); 
                });
                // this doesnt! although i see in the former array that there are options
                // with the poll_id set to 1.
                Option.find({'poll_id':1}).exec(function(err,docs){
                    console.log(docs); 
                });

            }
            res.json(polls);
        }
    });
};

Что я делаю не так? Я просмотрел его, но я не вижу ни одного поста, относящегося к моей проблеме. я пытался использовать model.find().where('poll_id').equals(1) с кавычками и без них, но ничего. когда я запускаю model.find(), он работает, но независимо от того, как я пытаюсь его отфильтровать, он возвращает пустой массив. заранее спасибо!


person David Nelband    schedule 09.12.2014    source источник
comment
Это классический случай условий гонки. Цикл for в вашем контроллере выполняется параллельно с вашим вызовом res.json, что означает, что сервер отвечает на запрос клиента до завершения выполнения первого цикла. Вам нужно реструктурировать код. Я бы посоветовал взглянуть на библиотеку async.   -  person srquinn    schedule 09.12.2014
comment
как бы вы предложили мне реструктурировать мой код в этом случае? вставить res.json в обратный вызов? извините за мою неосведомленность в этом вопросе   -  person David Nelband    schedule 09.12.2014
comment
1) Никогда не извиняйтесь за то, что задаете вопросы — предполагается, что вы задаете вопрос о SO, потому что вы учитесь. Любой на этом форуме, который упрекает вас за то, что вы задаете вопросы, упускает суть. 2) Не могли бы вы написать на простом английском языке запрос, который вы пытаетесь выполнить? У вас есть пара проблемных областей в вашем контроллере, и прежде чем я смогу протянуть руку помощи, было бы неплохо узнать вашу цель.   -  person srquinn    schedule 09.12.2014
comment
так что в основном у меня есть страница со списком опросов коллекции опросов. у каждого опроса есть параметры, хранящиеся в другом наборе, наборе параметров. каждый документ в коллекциях параметров имеет 3 поля, одно из них — poll_id, который является идентификатором опроса, к которому относится этот параметр. Итак, я хочу, чтобы каждый опрос в списке опросов имел массив своих опций, которые мне нужно получить по атрибуту poll_id (этот проект импортирован из MySql, поэтому я не могу использовать атрибут obeject._id на данный момент). большое спасибо!   -  person David Nelband    schedule 10.12.2014


Ответы (1)


Я понимаю, что вы импортировали из MySQL, но правильный способ хранения и поиска ваших данных с помощью Mongoose будет с населением и ссылками:

var Polls = mongoose.Schema({
  options: [{ type: Schema.Types.ObjectId, ref: 'Options' }]
});

var Options = mongoose.Schema({
  ...
});

Polls
  .find()
  .limit(10)
  .sort('_id')
  .populate('options')
  .exec(function (err, polls) {
    console.log(polls.options); // => [ array of options ]
  });

Соответствующие документы можно найти здесь http://mongoosejs.com/docs/populate.html.

Я настоятельно рекомендую потратить некоторое время на реструктуризацию ваших данных, чтобы вы могли использовать многие преимущества заполнения и ссылок (индексирование, более чистый код и т. д.). Не совершайте ошибку, пытаясь навязать реляционную парадигму хранилищу документов. Полностью разорвите помощника по оркестру или придерживайтесь того, что у вас есть и что вы знаете.

Тем не менее, вы можете достичь того, что ищете, с вашими текущими данными, например:

// npm install --save async
var async = require('async');

exports.list = function(req, res, next) {

  Poll.find().limit(10).sort('_id').exec(function (err, polls) {

    // In true HTTP parlance, the correct thing to do here would 
    // be to respond with a 500 instead of a 400. The error would
    // be coming from MongoDB, not a poorly formed request by the
    // client. Remember: 40Xs are for client errors and 50Xs are 
    // for server errors. If this is express, you should also look
    // into using a middleware error handler and passing the error 
    // down the line like so:
    if (err) return next(err);

    // Since you used a return statement above, there is no need for 
    // the if/else but this is a matter of style. If it helps with the
    // readability of your code, keep it. I choose to eliminate because
    // async code has enough nesting as it is!

    // https://github.com/caolan/async#maparr-iterator-callback
    async.map(polls, function (poll, callback) {

      // Now look up your option by its poll_id
      Option.find({'poll_id': poll.poll_id}, function (err, options) {
        if (err) return callback(err);
        poll.options = options;
        callback(null, poll);
      });

    }, function (err, data) {

      // Again, this would be a Mongo error, so pass it down the line to
      // handle as a generic 500.
      if (err) return next(err);

      // The data parameter is your newly mapped polls array
      res.json(data);

    });
  });
};    

Обратите внимание на то, насколько больше шаблонов потребовалось для создания без населения и рефов. Кроме того, население под прикрытием попадет в DB только дважды, тогда как здесь вы попадаете в него 11 раз. В долгосрочной перспективе вам будет лучше изменить свои данные сейчас, чем создавать гибрид реляционного/хранилища документов. Я их видела, они некрасивые ;)

person srquinn    schedule 10.12.2014
comment
я принимаю этот ответ только потому, что вы были принципиально правы, полностью снимите повязку! но решение не сработало. я прошел долгий (или не очень) путь оттуда, но снова столкнулся с проблемой, на следующем шаге. если вы хотите снова помочь - › заголовок stackoverflow.com/questions/27464146/ :) - person David Nelband; 14.12.2014
comment
@DavidNelband Я рад, что ты что-то понял из ответа. Я не разработчик стека MEAN, потому что терпеть не могу Angular. ИМО должно быть строгое разделение между бизнес-логикой и шаблонами. В этом отношении: встроенный javascript, такой как onclick="blah()", считается плохой практикой, так в чем же разница с ng-click="blah" помимо присущей области? Нада. - person srquinn; 14.12.2014