Mongoose Populate возвращает значение null или undefined

Прошу прощения, если это серьезный вопрос, я уже несколько часов ищу в Google и Stack, и мне нужно спросить!

У меня есть две схемы, User и Story, показанные ниже. Я пытаюсь ссылаться на пользователя для истории, используя опцию Ref для заполнения в запросе - я использовал mySQL раньше и поэтому хотел попытаться воспроизвести оператор JOIN. Всякий раз, когда я пытаюсь использовать заполнение, я просто получаю возвращаемый objectID или null (как показано ниже).

Изменено 12 ноября: исправлены жестко заданные идентификаторы и добавлены данные консоли

story-schema.js

var mongoose = require('mongoose'),
Schema = mongoose.Schema,
User = require('./user-schema');

var StorySchema = new Schema({  
title: { type: String, required: true },  
author_id: { type: Schema.Types.ObjectId, ref: 'User' },
summary: { type: String, required: true },
rating: { type: String, required: true }
});

module.exports = mongoose.model('Story', StorySchema, 'stories');

user-schema.js

var mongoose = require('mongoose'),
Schema = mongoose.Schema;

var UserSchema = new Schema({
    username: { type: String, required: true, index: { unique: true } },
    is_admin: {type: Boolean, required: true, default: false }
});

сохранить - идентификатор жестко задан, например

app.post('/api/new_story', function(req, res){
var story;
story = new Story({
    title: req.body.title,
    author_id: mongoose.Types.ObjectId(req.params._id), 
            /* ex of req.params._id: 527fc8ff241cdb8c09000003*/
    summary: req.body.summary,
    rating: req.body.rating
});

story.save(function(err) {
    if (!err) {
        return console.log("created");
    } else {
        return console.log(err);
    }
});
return res.send(story);
});

пример пользователя при входе в терминал

{
"__v" : 0,
"_id" : ObjectId("527fc8ff241cdb8c09000003"),
"is_admin" : false,
"username" : "ted"
}

пример истории при входе в терминал

{
"title" : "Test Story",
"author_id" : "527fc8ff241cdb8c09000003",
"summary" : "Test summary",
"rating" : "12",
"_id" : ObjectId("52827692496c16070b000002"),
"__v" : 0
}

запросы

//other mongoose/app includes above
User = require('./config/schema/user-model'),
Story = require('./config/schema/story-model');

// data.author_id = 527fc8ff241cdb8c09000003 
// data.author_id.username = undefined
app.get('/api/query/:id', function (req, res){
return Story.findOne({_id:req.params.id})
.populate( { path: 'User' } )
.exec(function (err, data) {
            console.log(data.author_id);
            console.log(data.author_id.username);
          if (err) {
            return res.json({error:err})
          }
        })
});

// data.author_id = null 
app.get('/api/query2/:id', function (req, res){
return Story.findOne({_id:req.params.id}) //_id hardcoded for example
.populate( 'author_id' )
.exec(function (err, data) {
            console.log(data.author_id);
          if (err) {
            return res.json({error:err})
          }
        })
});

В первом запросе я получаю author_id, который я уже сохранил, что имеет смысл, поскольку это то, что я сохранил, но я получаю доступ к имени пользователя.

Во втором запросе я даже не могу получить доступ к author_id, который я уже сохранил.

Изменить: я могу нормально выполнить обычный запрос GET без "заполнить"

Что бы я хотел сделать

Возможность получить доступ к информации об авторе из рассказа - это больше похоже на доказательство концепции. В конце концов, я хотел бы сослаться на Story _id в модели User, поскольку для пользователя может быть много историй, но только один пользователь на историю, но я подумал, что сначала начну с этого.


person lucirebecca    schedule 11.11.2013    source источник


Ответы (8)


Поскольку ваш пример включает необработанные идентификаторы объектов, которые даже не указаны как допустимые строки javascript, трудно понять, что является ошибкой в ​​вашем вопросе по сравнению с ошибкой в ​​вашем коде, но в основном ваш второй запрос выглядит так, как будто он должен работать. Я подозреваю, что вы путаете значения ObjectId. Вы используете один и тот же ObjectId для своей истории и своего пользователя, и это не сработает:

   author_id: mongoose.Types.ObjectId(528149b38da5b85003000002),

Это тот же идентификатор, который вы используете для поиска истории. Итак, я думаю, что исправление:

  1. Убедитесь, что у вас есть действующая запись пользователя в коллекции пользователей.
  2. Убедитесь, что запись story.author_id вашей тестовой истории соответствует этому
  3. Убедитесь, что вы ищете историю по идентификатору истории, а не по author_id.

Если вы все еще не можете заставить это работать, закодируйте все это в одном .js файле с обеими схемами, обеими моделями и некоторым кодом для создания записей, затем выполните запросы и опубликуйте их.

person Peter Lyons    schedule 11.11.2013
comment
Привет, я обновил примеры, чтобы не иметь жестко закодированных данных - это была ошибка копирования и вставки в моих усилиях, чтобы сделать вещи более ясными (сбой). Я могу вернуть действительную запись пользователя, пытаясь вернуть только пользователя (1). Author_id совпадает с _id пользователя, однако, хотя я пытаюсь сохранить его как ObjectID, он отображается в консоли в виде строки. Может ли это быть? - person lucirebecca; 12.11.2013
comment
Хорошо, так что да, я думаю, что проблема в том, что story.author_id - это String, а не ObjectId. Это проблема с данными, которую вам нужно просто исправить, загрузив и повторно сохранив эту запись. Я предполагаю, что вы создали эту историю либо до того, как ваша схема mongoose была завершена, либо через оболочку mongo или что-то еще, но по сути данные не соответствуют схеме, что всегда представляет собой риск для этого типа базы данных. - person Peter Lyons; 12.11.2013
comment
Хорошо, я создал новую запись, но все равно не повезло, затем я попробовал свежую схему, свежую коллекцию на всякий случай, но без радости. После этого я засунул все в один файл, как в вашем первом комментарии, и он работает (!) С исходным /api/query2/:id и т. Д. - Я думаю, что это должно быть связано с отдельными файлами, которые требуются друг для друга - я нашел этот ответ ссылка, но это не сработало для меня либо при разделении их на части. Так что сейчас это 1 файл! - person lucirebecca; 13.11.2013
comment
Ах, да, вы, вероятно, создали круговой граф требований, который является узлом запрета. Не используйте require для ссылки на каждую модель друг в друге, просто используйте имя строковой модели в ссылках на схему. - person Peter Lyons; 13.11.2013
comment
Вот и все! Большое спасибо! - person lucirebecca; 13.11.2013

Я застрял с этой проблемой на неделю. Попробовав все и убедившись, что у меня нет циклических ссылок, я решил сбросить свою БД.

После удаления всех коллекций и их повторного сохранения все мои отношения, управляемые populate() мангуста, работали.

Это так неприятно, потому что эта проблема не задокументирована, и я потерял 20-30 часов, пытаясь создать дурацкую справочную коллекцию.

person Bobzius    schedule 17.03.2019
comment
Сейчас мы сталкиваемся с аналогичной проблемой. Мы не вносили никаких изменений в версию mongoose, по-прежнему возвращая null для некоторых случаев populate (), которые работали нормально последние 4 года. - person Arun s; 04.03.2021
comment
то же самое здесь я использую метод Model.populate() .... - person adir abargil; 13.05.2021

Возможно ли, что вы забыли включить поле «ref» в свою схему? Я только что столкнулся с этой проблемой, и после добавления поля ref в мою схему он сразу работает без необходимости сбрасывать базу данных. Надеюсь, эта информация поможет.

Я нашел здесь документальный пример: https://mongoosejs.com/docs/3.0.x/docs/populate.html. Хотя это документация для версии 3.0.x, я счел ее полезной даже для версии 5.5.5, которую я сейчас использую.

person Leo Yang    schedule 04.05.2019
comment
После нескольких часов отладки и изучения до смешного ужасных документов Mongoose этот ответ, наконец, дал намек о необходимости ссылок. Спасибо, Лео. FML. - person o01; 08.10.2020

Если ваших данных очень мало, попробуйте очистить данные из таблиц, связанных с заполнением и основной.

person Mehedi Hasan    schedule 23.02.2021

Я застрял в этой задаче 5-6 часов и нашел для нее очень простое решение. В этом случае вы можете увидеть здесь:

    {
   "title" : "Test Story",
   "author_id" : "527fc8ff241cdb8c09000003",
   "summary" : "Test summary",
   "rating" : "12",
   "_id" : ObjectId("52827692496c16070b000002"),
   "__v" : 0
   }

в значении author_id '527fc8ff241cdb8c09000003' - это в основном строка, а не ObjectId. Это происходит, когда вы восстанавливаете базу данных из json или csv, и во время этого процесса ObjectId преобразуется в строку. В моем случае я сбросил данные с помощью Python и пытаюсь получить данные с помощью экспресс. Итак, чтобы решить эту проблему, я просто обновил данные, используя экспресс, и теперь Populate работает, попробуйте обновить данные:

 const { ObjectId }  = require('bson');
    app.get('/update-data', (req,res)=>{
         Story.find()
        .exec((err,posts)=>{
            for(let value of posts)
            {
             User.findOne({ _id : value.author_id })
             exec((err,userData)=>{
                      Story.update({ _id : value._id }, {  author_id : ObjectId(userData._id) })
              .exec((error, resData)=>{
                   console.log(resData);
                 });
               })
            
            }
            res.send('Data Updated, try populating data again');
        });
    });
    

и все, после восстановления связи с пользователем попробуйте снова заполнить поле.

Обновление 1:
Я забыл упомянуть, что необходимый пакет для ObjectId () должен включать это

const { ObjectId }  = require('bson');

Обновление 2: покопавшись глубже, я обнаружил, что обновление не является решением. Я обнаружил, что вам нужно включить всю модель, которую вы хотите заполнить. например: есть countryModel, которая связана с пользователем. то в модель страны кода и модель пользователя оба должны быть включены следующим образом:

var userModel = require('../<path to model>/userModel');
var countryModel = require('../<path to model>/countryModel');

однако вы не используете countryModel, но это необходимо инициировать. Код модели страны должен быть: countryModel.js.

const mongoose = require('mongoose');

const countrySchema = mongoose.Schema({
country_name : String,
flag_image : String,
country_code : String
});

//user model 
var countryModel = mongoose.model('countries', countrySchema);
module.exports = countryModel;
person Technical Heist    schedule 08.03.2021

Во-первых, это происходит, когда вы добавляете метод populate после создания некоторых коллекций.

Вы можете сделать новый запрос и создать новые коллекции для подключенных моделей (всех). Тогда должен работать метод заполнить.

Ранее созданные модели по-прежнему будут отправлять null, но вновь созданные коллекции должны возвращать заполненные данные.

person Mahadi Hassan    schedule 02.05.2021

Я наткнулся на это, и проблема заключалась в ссылке на удаленный документ. сбросьте свою БД, если можете, или дважды проверьте указанный идентификатор

person yooneskh    schedule 03.09.2019

Мне удалось решить эту проблему, объявив ref как ссылку на класс модели вместо строки с именем модели.

// before
let Schema = mongoose.Schema({
    name: String,
    author: { type: Schema.Types.ObjectId, ref: 'Author' }
});

//after
let Schema = mongoose.Schema({
    name: String,
    author: { type: Schema.Types.ObjectId, ref: Author }
});
person CORSAIR    schedule 25.02.2020
comment
Вы должны включить / потребовать класс, на который хотите ссылаться, это всего лишь пример. Не просто понижайте ответ, а попробуйте проанализировать пример. - person CORSAIR; 22.05.2020