Search code examples
mongodbjoinforeign-keysmongoose

Understanding Relationships & Foreign Keys in Mongoose


In MongoDB/Mongoose, how do I define a relationship? I think there are a few ways I've seen, but I'm not sure I understand the differences or when do I use which. I am using Mongoose 3

I've defined Todo and TodoList model, where the relationship is obvious. So following the docs http://mongoosejs.com/docs/documents.html, I've defined classes like:

# Todo.coffee
mongoose = require "mongoose"

todoSchema = mongoose.Schema
    name: String
    desc: String
    dueOn: Date
    completedOn: Date

module.exports = mongoose.model "Todo", todoSchema

# TodoList.coffee

mongoose = require "mongoose"
Todo = require "./Todo"

todoListSchema = mongoose.Schema
    name: String
    todos: [Todo.schema]

module.exports = mongoose.model "TodoList", todoListSchema

Then I tried testing the classes:

list = new TodoList
    name: "List 1"
    todos: [
        { name: "Todo 1", desc: "Hello", dueOn: new Date(2012,10,1), completedOn: new Date(2012,10,2) }
        { name: "Todo 2" }
        { name: "Todo 3", desc: "Hello 2", dueOn: new Date(2012,10,6), completedOn: new Date(2012,10,2) }
        { name: "Todo 4" }
    ]
#list.todos.push { name: "Todo 5" }
console.log "List", list
list.save (err) ->
    if !err
        TodoList.find {}, (err, lists) ->
            console.log "TODOS"
            console.log lists.length, lists
            done(err)
    else 
        console.log "ERROR!!!"
        done err

When I try to do Todo.find() I get nothing, so the Model (Todo.coffee) is kind of redundant? It looks like Todo are stored in TodoList, as a user I may not care, but I wonder what are the implications? Eg. will the document get too large? 1 TodoList with too many Todos? Does that matter? What if I allow nested Todos (not that I want to do itm just for understanding), is it better to store documents separately then? How do I do that, if I so desire, and when do I do it?

I saw another method, in Mongoose 2 actually. I don't know, if it is possible in 3. Something like using ObjectId instead of nested docs. Maybe thats to store it separately?


Solution

  • I'm still new to Node, Mongoose, and Mongo, but I think I can address at least part of your question. :)

    Your current method is the same as I tried doing at first. Basically, it ends up storing it very similarly to this (written in JS, since I don't know CoffeeScript):

    var todoListSchema = new mongoose.Schema({
        name: String,
        todos: [{
            name: String,
            desc: String,
            dueOn: Date,
            completedOn: Date
        }]
    });
    

    I later found this method, which is what I was looking for, and I think what you were intending:

    var todoListSchema = new mongoose.Schema({
        name: String,
        todos: [{
            type: mongoose.Schema.Types.ObjectId,
            ref: 'Todo' //Edit: I'd put the schema. Silly me.
        }]
    });
    

    This stores an array of ObjectIds, which you can then load using Query#populate in Mongoose.

    I don't know of the technical implications, but it makes more sense in my brain if I keep them separate, so that's what I'm doing. :)

    Edit: Here is a some official docs that might be useful: http://mongoosejs.com/docs/populate.html