Referencing another schema in Mongoose

JavascriptMongodbMongoose

Javascript Problem Overview


if I have two schemas like:

var userSchema = new Schema({
	twittername: String,
	twitterID: Number,
	displayName: String,
	profilePic: String,
});

var  User = mongoose.model('User') 

var postSchema = new Schema({
    name: String,
    postedBy: User,  //User Model Type
    dateCreated: Date,
    comments: [{body:"string", by: mongoose.Schema.Types.ObjectId}],
});

I tried to connect them together like the example above but I couldn't figure out how to do it. Eventually, if I can do something like this it would make my life very easy

var profilePic = Post.postedBy.profilePic

Javascript Solutions


Solution 1 - Javascript

It sounds like the populate method is what your looking for. First make small change to your post schema:

var postSchema = new Schema({
    name: String,
    postedBy: {type: mongoose.Schema.Types.ObjectId, ref: 'User'},
    dateCreated: Date,
    comments: [{body:"string", by: mongoose.Schema.Types.ObjectId}],
});

Then make your model:

var Post = mongoose.model('Post', postSchema);

Then, when you make your query, you can populate references like this:

Post.findOne({_id: 123})
.populate('postedBy')
.exec(function(err, post) {
    // do stuff with post
});

Solution 2 - Javascript

Addendum: No one mentioned "Populate" --- it is very much worth your time and money looking at Mongooses Populate Method : Also explains cross documents referencing

http://mongoosejs.com/docs/populate.html

Solution 3 - Javascript

Late reply, but adding that Mongoose also has the concept of Subdocuments

With this syntax, you should be able to reference your userSchema as a type in your postSchema like so:

var userSchema = new Schema({
    twittername: String,
    twitterID: Number,
    displayName: String,
    profilePic: String,
});

var postSchema = new Schema({
    name: String,
    postedBy: userSchema,
    dateCreated: Date,
    comments: [{body:"string", by: mongoose.Schema.Types.ObjectId}],
});

Note the updated postedBy field with type userSchema.

This will embed the user object within the post, saving an extra lookup required by using a reference. Sometimes this could be preferable, other times the ref/populate route might be the way to go. Depends on what your application is doing.

Solution 4 - Javascript

{body: "string", by: mongoose.Schema.Types.ObjectId}

The mongoose.Schema.Types.ObjectId will create a new id, try changing it to more direct type, like String or Number.

Solution 5 - Javascript

This is in addition to D. Lowe's answer which worked for me but needed a bit of tweaking. (I would have put this as a comment but I don't have the reputation to do so, and I would like to see this information in a few months when I encounter this issue again but I forget how to solve it.)

If you are importing a Schema from another file, then you will need to add .schema to the end of the import.

Note: I am unsure if you get the Invalid schema configuration if you are not importing schemas and using local schemas instead but importing is just cleaner and easier to handle for me.

For example:

// ./models/other.js
const mongoose = require('mongoose')

const otherSchema = new mongoose.Schema({
    content:String,
})

module.exports = mongoose.model('Other', otherSchema)

//*******************SEPERATE FILES*************************//

// ./models/master.js
const mongoose = require('mongoose')

//You will get the error "Invalid schema configuration: `model` is not a valid type" if you omit .schema at the end of the import
const Other=require('./other').schema


const masterSchema = new mongoose.Schema({
    others:[Other],
    singleOther:Other,
    otherInObjectArray:[{
        count:Number,
        other:Other,
    }],
})

module.exports = mongoose.model('Master', masterSchema);

Then, wherever you use this (for me I used code similar to this in my Node.js API) you can simply assign other to master.

For example:

const Master= require('../models/master')
const Other=require('../models/other')

router.get('/generate-new-master', async (req, res)=>{
    //load all others
    const others=await Other.find()

    //generate a new master from your others
    const master=new Master({
        others,
        singleOther:others[0],
        otherInObjectArray:[
            {
                count:1,
                other:others[1],
            },
            {
                count:5,
                other:others[5],            
            },
        ],
    })

    await master.save()
    res.json(master)
})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questions_curry_sView Question on Stackoverflow
Solution 1 - JavascriptnicksweetView Answer on Stackoverflow
Solution 2 - JavascriptfinoView Answer on Stackoverflow
Solution 3 - JavascriptD. LoweView Answer on Stackoverflow
Solution 4 - JavascriptSpadefaithView Answer on Stackoverflow
Solution 5 - JavascriptDisplay nameView Answer on Stackoverflow