baskerville42
@baskerville42
Учусь работать (Junior)

Как сделать populate (join) двух коллекций в Mongoose?

Нужно сделать джоины двух коллекций в третью и делать выборку данных через .populate() (MongooseJS) с этой третей коллеции. По этому мануалу разобрался как это реализовать и способ вполне устроил. Осталась маленькая проблема, а точнее специфика задачи которую я решаю.
var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/test');

var youTubeSchema = Schema({
    id: String,
    _trailer: { type: Schema.Types.ObjectId, ref: 'Trailer' }
});

var postersSchema = Schema({
    posters: String,
    _trailer : { type: Schema.Types.ObjectId, ref: 'Trailer' }
});

var trailerSchema = Schema({
    timestamp: String,
    _youtube : { type: Schema.Types.ObjectId, ref: 'YouTube' },
    _posters : { type: Schema.Types.ObjectId, ref: 'Posters' }
});

var YouTube  = mongoose.model('YouTube', youTubeSchema);
var Posters = mongoose.model('Posters', postersSchema);
var Trailer = mongoose.model('Trailer', trailerSchema);

var trailer = new Trailer({
    timestamp: new Date()
});

trailer.save(function (err) {
    if (err) return handleError(err);

    var youtube = new YouTube({
        id: "rTCxSguAmjQ",
        _trailer: trailer._id
    });

    youtube.save(function (err) {
        if (err) return handleError(err);
    });

    var posters = new Posters({
        posters: "4j3h34hg34ygyu34gkj43h.jpg",
        _trailer: trailer._id
    });

    posters.save(function (err) {
        if (err) return handleError(err);
    });
});


Этот кусочек кода сохраняет все данные как мне нужно (ну почти, как мне нужно). Единственное что я не могу решить, как делать поиск из коллекции Trailers, что бы потом данные подтягивались из коллекций YouTube, Posters.
YouTube
    .findOne({ _id: '5502a5cf57e8ca2c0b58962d' })
    .populate('_trailers')
    .exec(function (err, trailer) {
        if (err) return handleError(err);
        console.log(trailer._trailer);
    });


Над задачей уже долго бьюсь, и ответ уже не вижу. Как сохранять данные таким образом, что бы я мог потом при поиске в моделе Trailers сразу видеть данные из YouTube и Posters.

Пробовал сразу обновлять документ после сохранения данных, но способ явно не правильный и не нравится мне.
Trailer.update({_id: '5502a5cf57e8ca2c0b58962d'}, {_youtube: youtube._id, _posters: posters._id}, {upsert: true}, function (err) {
    if (err) return handleError(err);
});


Здесь окончательная версия, которая работает как надо но сделанная не изящным способом

PS: Знаю что в монге сделать джоины без особых ухищрений нельзя, хочу решить проблему как есть, а не менять СУБД.
  • Вопрос задан
  • 5890 просмотров
Пригласить эксперта
Ответы на вопрос 1
@dimonnwc3
Я не до конца понимаю вопрос, но попробую ответить, как я понял.
Есть Трейлеры, которые имеют ID видео на ютубе, и путь к постеру(jpg).

По сути, сама схема построена не правильно
Для чего используются отдельные коллекции YouTube и Posters ?

Основной документ это трейлер, он имеет одну ссылку на ютуб и один постер, но в теории может иметь и больше.
Сылка на ютуб и адрес постера, не могут иметь болеу одного трейлера(не могут принадлежать более чем одному трейлеру), более того они всегда уникальны и привязаны к трейлеру.

Можно сделать ОДНУ вложенную схему вместо трех, без ссылок DBref.

var trailerSchema = Schema({
    timestamp: String,
    youtube : String
    poster : String
});


Либо если трейлер, может иметь много постеров, то с помощью массива объектов:
var trailerSchema = Schema({
    timestamp: String,
    youtube :  [{name: String, url: String}]
    posters : [{name: String, url: String}]
});


так запрос:
Trailer.find(query);
Будет сразу выдавать информацию, со ссылками на ютуб и постеры, без популяции.

Не нужно пытаться эмулировать джоины и использовать коллекции, как таблиц, там где это не требуется.

PS. С DBref это тоже можно сделать, но я не вижу в этом примере смысла.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы