Blog

Using MongooseJS to Create Associations Among MongoDB Collections
Posted on July 21, 2015 in MongoDB, Node.js by Matt Jennings

Below is example code using MongooseJS, other Node.js modules, and a MongoDB database to create associations among MongoDB collections.

package.json code

{
  "name": "messure-board-with-mongoosejs",
  "version": "0.0.1",
  "description": "Message Board using MongooseJS",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/Hollyw00d/message-board-with-mongoosejs"
  },
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "body-parser": "1.13.x",
    "ejs": "2.3.x",
    "express": "4.13.x",
    "mongoose": "4.0.x"
  }
}

server.js code

// Require path
var path = require("path");

// Require express and create express app
var express = require("express");
var app = express();

// Require body-parser to be able to send POST data
var bodyParser = require("body-parser");
app.use(bodyParser.urlencoded( {extended: true} ));

// Static content
app.use(express.static(path.join(__dirname + "/static")));

// Set up views directory and ejs
app.set("views", path.join(__dirname + "/views"));
app.set("view engine", "ejs");

// Require mongoose
var mongoose = require("mongoose");

// Create/connect to "dojo_message_board"
// database
mongoose.connect("mongodb://localhost/dojo_message_board");

// Create schema to start associations,
// similar to MySQL joins
var Schema = mongoose.Schema;

var messageSchema = new mongoose.Schema({
    name: String,
    message: String,
    // Code below creates a
    // "created_at" date
    created_at: {type: Date, default: new Date},
    // Line below is used to associate
    // a message "_id" to a
    // comment "_id" which is
    // like a foreign key
    comments: [{type: Schema.Types.ObjectId, ref: "Comment"}]
});

var commentSchema = new mongoose.Schema({
    // Line below is used to associate
    // the message "_id" to a comment "_id"
    // and notice the underscore
    // in "_message" to associate this "_id"
    // with the "messageSchema"
    _message: {type: Schema.ObjectId, ref: "Message"},
    name: String,
    comment: String,
    // Code below creates a
    // "created_at" date
    created_at: {type: Date, default: new Date}
});

// "Message" and "Comment" objects below
// will give me objects to
// take actions on the MongoDB database AND
// the "Message" parameter needs to match the 'ref: "Message"'
// property value AND
// the "Comment" parameter needs to match the 'ref: "Comment"'
// property value
var Message = mongoose.model("Message", messageSchema);
var Comment = mongoose.model("Comment", commentSchema);

// Home page
app.get("/", function(req, res) {
    //res.render("index");

    // Display all documents from
    // the "messages" collection on the
    // home page
    Message.find({}).populate("comments").exec(function(err, messages) {
        if(err) {
            console.log("Error:", err);
        }
        else {
            // Reverses order of properties
            // in an array of objects
            messages.reverse();
            res.render("index", {messages: messages});
        }
    });
});

// Post message
app.post("/messages", function(req, res) {
    console.log("Message Posted:", req.body);

    var message = new Message({
        name: req.body.name,
        message: req.body.message
    });

    message.save(function(err) {
        if(err) {
            console.log("Error:", err);
        }
        else {
            res.redirect("/");
        }

    });

});

// Post comment using the "_id" field
// from the "messages" collection
app.post("/message/:id", function(req, res) {

    // Show post of comment form in terminal
    console.log("Comment Posted:", req.body);

    // Code to post one comment related to one
    // message via the message id
    Message.findOne( {_id: req.params.id}, function(err, message) {

        var comment = new Comment(req.body);

        comment._message = message._id;

        message.comments.push(comment);

        comment.save(function(err) {
            message.save(function(err) {

                if(err) {
                    console.log("Comment Error", err);
                }
                else {
                    res.redirect("/");
                }

            });

        });

    });

});

// Listen on port 8000
app.listen(8000, function() {
    console.log("Node.js is running on port 8000");
});

index.ejs code

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>The Dojo Message Board</title>
    <link rel="stylesheet" type="text/css" href="css/styles.css"/>
</head>
<body>

<div id="wrapper">

    <h1>The Dojo Message Board</h1>

    <hr/>

    <form id="message-form" action="/messages" method="post">
        <p>
            <label for="name">Name:</label><br />
            <input type="text" name="name"/>
        </p>
        
        <p>
            <label for="message">Message:</label><br />
            <textarea name="message"></textarea>
        </p>

        <p>
            <input type="submit" value="Post message"/>
        </p>

    </form>

    <hr/>

    <%
    // For in loop to iterate over all
    // documents in the "messages"
    // collection from the newest to
    // oldest message
    %>
    <% for(var msg in messages) {  %>

        <div class="message">
            <h2>Name: <%= messages[msg].name; %></h2>
            <h3>Message: &ldquo;<%= messages[msg].message; %>&rdquo;</h3>

                <div class="comment">

                    <%
                    // Month names in an array
                    var monthName = [
                        "January",
                        "February",
                        "March",
                        "April",
                        "May",
                        "June",
                        "July",
                        "August",
                        "September",
                        "October",
                        "November",
                        "December"
                    ];

                    // For loop to
                    // iterate over all
                    // comment(s) of an associated
                    // message
                    %>
                    <% for(var j = messages[msg].comments.length -1; j > -1; j--) { %>
                        <p><strong>Name:</strong> <%= messages[msg].comments[j].name; %><br /><strong>Comment:</strong> <%= messages[msg].comments[j].comment; %><br />
                        <strong>Date Posted:</strong> <%= messages[msg].comments[j].created_at.getHours(); %>:<%= ("0" + messages[msg].comments[j].created_at.getMinutes()).slice(-2) %>, <%= monthName[messages[msg].comments[j].created_at.getMonth()]; %> <%= messages[msg].comments[j].created_at.getDate(); %>, <%= messages[msg].comments[j].created_at.getFullYear(); %>
                        </p>

                    <% } %>

                    <form class="comment-form" action="/message/<%= messages[msg]._id %>" method="post">
                        <p><label for="name">Name:</label><br />
                            <input type="text" name="name"/></p>
                        <p><label for="comment">Comment:</label><br />
                            <textarea name="comment"></textarea></p>
                        <p><input type="submit" value="Post comment"/></p>

                    </form>
                </div>


            <hr />


        </div>


    <% } %>


</div>

</body>
</html>

Leave a Reply