A
A
Alexander Tartmin2015-03-13 14:11:41
MongoDB
Alexander Tartmin, 2015-03-13 14:11:41

How to populate (join) two collections in Mongoose?

You need to join two collections into a third one and fetch data via .populate() (MongooseJS) from this third collection. According to this manual, I figured out how to implement it and the method is quite satisfied. There was a small problem, or rather the specifics of the problem that I solve.

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);
    });
});

This piece of code saves all the data as I need (well, almost as I need). The only thing I can't decide is how to search from the Trailers collection, so that the data would then be pulled from the YouTube, Posters collections.
YouTube
    .findOne({ _id: '5502a5cf57e8ca2c0b58962d' })
    .populate('_trailers')
    .exec(function (err, trailer) {
        if (err) return handleError(err);
        console.log(trailer._trailer);
    });

I've been struggling with the problem for a long time, and I don't see the answer anymore. How to save the data in such a way that when I search in the Trailers model, I can immediately see the data from YouTube and Posters.
I tried to immediately update the document after saving the data, but the method is clearly not correct and I do not like it.
Trailer.update({_id: '5502a5cf57e8ca2c0b58962d'}, {_youtube: youtube._id, _posters: posters._id}, {upsert: true}, function (err) {
    if (err) return handleError(err);
});

Here is the final version, which works as it should, but not done in an elegant way
PS: I know that it is impossible to make joins in monge without special tricks, I want to solve the problem as it is, and not change the DBMS.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Dmitrii Solovev, 2016-02-06
@dimonnwc3

I don't fully understand the question, but I'll try to answer the way I understand it.
There are trailers that have a YouTube video ID and a path to the poster (jpg).
In fact, the scheme itself is not built correctly.
What are the separate collections of YouTube and Posters used for?
The main document is the trailer, it has one YouTube link and one poster, but in theory it could have more.
Youtube link and poster address cannot have more than one trailer (can't belong to more than one trailer), moreover they are always unique and tied to a trailer.
You can make ONE nested schema instead of three, without DBref references.

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

Or if the trailer can have many posters, then using an array of objects:
var trailerSchema = Schema({
    timestamp: String,
    youtube :  [{name: String, url: String}]
    posters : [{name: String, url: String}]
});

so the request:
Will immediately issue information, with links to YouTube and posters, without a population.
No need to try to emulate joins and use collections as tables where it is not required.
PS. With DBref, this can also be done, but I do not see the point in this example.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question