Mongoose: заполнение населенного поля
Я использую MongoDB в качестве хранителя журнала для своего приложения, чтобы затем синхронизировать мобильные клиенты. У меня эти модели установлены в NodeJS:
var UserArticle = new Schema({
date: { type: Number, default: Math.round((new Date()).getTime() / 1000) }, //Timestamp!
user: [{type: Schema.ObjectId, ref: "User"}],
article: [{type: Schema.ObjectId, ref: "Article"}],
place: Number,
read: Number,
starred: Number,
source: String
});
mongoose.model("UserArticle",UserArticle);
var Log = new Schema({
user: [{type: Schema.ObjectId, ref: "User"}],
action: Number, // O => Insert, 1 => Update, 2 => Delete
uarticle: [{type: Schema.ObjectId, ref: "UserArticle"}],
timestamp: { type: Number, default: Math.round((new Date()).getTime() / 1000) }
});
mongoose.model("Log",Log);
Когда я хочу извлечь журнал, я использую следующий код:
var log = mongoose.model('Log');
log
.where("user", req.session.user)
.desc("timestamp")
.populate("uarticle")
.populate("uarticle.article")
.run(function (err, articles) {
if (err) {
console.log(err);
res.send(500);
return;
}
res.json(articles);
Как вы можете видеть, я хочу, чтобы mongoose заполнил поле "uarticle" из коллекции журнала, а затем я хочу заполнить поле "статья" в пользовательской статье ( "uarticle" ).
Но, используя этот код, Mongoose только заполняет "uarticle" , используя модель UserArticle, но не поле статьи внутри uarticle.
Можно ли выполнить его с помощью Mongoose и populate() или я должен сделать что-то еще?
Спасибо,
Ответы
Ответ 1
Из того, что я проверил в документации и из того, что я слышу от вас, этого не может быть достигнуто, но вы можете сами заполнить документы "uarticle.article" в функции обратного вызова.
Однако я хочу отметить еще один аспект, который я считаю более важным. У вас есть документы в коллекции. В какой справочной коллекции B, а в сборниках B есть другая ссылка на документы в коллекции C.
Вы либо делаете это неправильно (я имею в виду структуру базы данных), либо вы должны использовать реляционную базу данных, такую как MySQL здесь. Власть MongoDB полагается на то, что вы можете вставлять больше информации в документы, тем самым делая меньше запросов (имея свои данные в одной коллекции). Хотя ссылка на что-то в порядке, наличие ссылки, а затем другая ссылка не похоже на то, что вы используете все преимущества MongoDB здесь.
Возможно, вы хотели бы поделиться своей ситуацией и структурой базы данных, чтобы мы могли помочь вам больше.
Ответ 2
Для этого вы можете использовать плагин mongoose-deep-populate. Использование:
User.find({}, function (err, users) {
User.deepPopulate(users, 'uarticle.article', function (err, users) {
// now each user document includes uarticle and each uarticle includes article
})
})
Отказ от ответственности: я являюсь автором плагина.
Ответ 3
У меня возникла та же проблема, но после нескольких часов работы я нашел решение. Это может быть без использования внешнего плагина:)
applicantListToExport: function (query, callback) {
this
.find(query).select({'advtId': 0})
.populate({
path: 'influId',
model: 'influencer',
select: { '_id': 1,'user':1},
populate: {
path: 'userid',
model: 'User'
}
})
.populate('campaignId',{'campaignTitle':1})
.exec(callback);
}
Ответ 4
как насчет чего-то типа:
populate_deep = function(type, instance, complete, seen)
{
if (!seen)
seen = {};
if (seen[instance._id])
{
complete();
return;
}
seen[instance._id] = true;
// use meta util to get all "references" from the schema
var refs = meta.get_references(meta.schema(type));
if (!refs)
{
complete();
return;
}
var opts = [];
for (var i=0; i<refs.length; i++)
opts.push({path: refs[i].name, model: refs[i].ref});
mongoose.model(type).populate(instance, opts, function(err,o){
utils.forEach(refs, function (ref, next) {
if (ref.is_array)
utils.forEach(o[ref.name], function (v, lnext) {
populate_deep(ref.ref_type, v, lnext, seen);
}, next);
else
populate_deep(ref.ref_type, o[ref.name], next, seen);
}, complete);
});
}
meta utils грубо... хочу src?