简体   繁体   中英

Referencing another schema in Mongoose

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

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

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

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.

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

mongoose.Schema.Types.ObjectId将创建一个新的 id,尝试将其更改为更直接的类型,例如 String 或 Number。

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM