Referencing-another-schema-in-Mongoose

In this next example, I am going to create two new schemas that will demonstrate how to create a relationship to another schema: author and book. The book schema will contain a reference to the author schema.

Author.js

var authorSchema = mongoose.Schema({
  _id: mongoose.Schema.Types.ObjectId,
  name: {
    firstName: String,
    lastName: String
  },
  biography: String,
  twitter: String,
  facebook: String,
  linkedin: String,
  profilePicture: Buffer,
  created: {
    type: Date,
    default: Date.now
  }
});

var Author = mongoose.model("Author", authorSchema);

Above is the author schema that expands upon the concepts of the user schema that I created in the previous example. To link the Author and Book together, the first property of the author schema is an _id property that is an ObjectId schema type. _id is the common syntax for creating a primary key in Mongoose and MongoDB. Then, like the user schema, I’ve defined a name property containing the author’s first and last name.

Expanding upon the user schema, the author contains several other String schema types. I’ve also added a Buffer schema type that could hold the author’s profile picture. The final property holds the created date of the author; however, you may notice it is created slightly differently because it has defined a default value of “now”. When an author is persisted to the database, this property will be set to the current date/time.

Now let’s create a book schema that contains a reference to the author by using the ObjectId schema type:

Book.js

var bookSchema = mongoose.Schema({
  _id: mongoose.Schema.Types.ObjectId,
  title: String,
  summary: String,
  isbn: String,
  thumbnail: Buffer,
  author: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "Author"
  },
  ratings: [
    {
      summary: String,
      detail: String,
      numberOfStars: Number,
      created: {
        type: Date,
        default: Date.now
      }
    }
  ],
  created: {
    type: Date,
    default: Date.now
  }
});

var Book = mongoose.model("Book", bookSchema);

Now save some objects in this model

var jamieAuthor = new Author {
    _id: new mongoose.Types.ObjectId(),
    name: {
        firstName: 'Jamie',
        lastName: 'Munro'
    },
    biography: 'Jamie is the author of ASP.NET MVC 5 with Bootstrap and Knockout.js.',
    twitter: 'https://twitter.com/endyourif',
    facebook: 'https://www.facebook.com/End-Your-If-194251957252562/'
};

jamieAuthor.save(function(err) {
    if (err) throw err;

    console.log('Author successfully saved.');

    var mvcBook = new Book {
            _id: new mongoose.Types.ObjectId(),
            title: 'ASP.NET MVC 5 with Bootstrap and Knockout.js',
            author: jamieAuthor._id,
            ratings:[{
                summary: 'Great read'
            }]
    };

    mvcBook.save(function(err) {
        if (err) throw err;

        console.log('Book successfully saved.');
    });

    var knockoutBook = new Book {
            _id: new mongoose.Types.ObjectId(),
            title: 'Knockout.js: Building Dynamic Client-Side Web Applications',
            author: jamieAuthor._id
    };

    knockoutBook.save(function(err) {
        if (err) throw err;

        console.log('Book successfully saved.');
    });
});

The example starts by creating and saving a jamieObject that is created from anAuthor Model. Inside the save function of the jamieObject, if an error occurs, the application will output an exception. When the save is successful, inside the save function, the two book objects are created and saved. Similar to the jamieObject, if an error occurs when saving, an error is outputted; otherwise, a success message is outputted in the console.

To create the reference to the Author, both of the book objects reference the author schema’s _id primary key in the author property of the book schema.

The ObjectId data type specifies a link to another document in your database. For example, if you had a collection of books and authors, the book document might contain an ObjectId property that refers to the specific author of the document.

1> https://scotch.io/@ossaijad/how-to-do-join-operations-and-create-links-between-mongodb-collection

Take an example of a social-network https://github.com/PrinceDavis/mongodb-joins. The repo contains a working webservice that allow you to create users, posts, and comments. You can also fetch users, their friends, posts, post creators and comments.

Here’s my user model – src/models/user/user.js

const Schema = new mongoose.Schema({
  fullname: {
    type: String,
    required: true
  },
  username: {
    type: String,
    required: true
  },
  friends: [
    {
      type: mongoose.Schema.ObjectId,
      ref: "User"
    }
  ]
});

module.exports = mongoose.model("User", Schema);

Inside the above user model to create a reference to the ‘friends’ property – I am doing mongoose.Schema.ObjectId. And this ObjectId’s will reference the user schema’s _id primary key. This is because by default mongodb assigns the _id field to take mongoose.Schema.Types.ObjectId – even though I dont set it to be so explicitly. [See the other file “referencing-another-schema-in-Mongoose-1.md ]

Here I created a mongoose schema for user data, notice that the type of friends is itself a type of ObjectId and has a ref property, this is how mongoose perform collection linking or join or relationships. Each user would have a friends array which would hold id values of other friends that they are friends with. back in the all method in our controller where we call populate function on UserModel we are telling mongoose to swap the id values for the real collection that those values represent.

And then in my src/models/post/post.js

A post has comment and a user who created it. That is, a Post belong to a User, hence it’s ‘creator’ property will have its ref to User

const Schema = new mongoose.Schema({
  creator: { type: mongoose.Schema.ObjectId, ref: 'User', required: true },
  title: { type: String, required: true },
  body: { type: String, required: true }
}

module.exports = mongoose.model('Post', Schema)

And this is my comment.js file. A comment belong to a Post, hence the ‘post’ property will have its ref to Post

const Schema = new mongoose.Schema({
  post: { type: mongoose.Schema.ObjectId, ref: "Post" },
  body: { type: String, required: true }
});

module.exports = mongoose.model("Comment", Schema);

The ref attribute

DBRefs have the following fields:

$ref – The $ref field holds the name of the collection where the referenced document resides.

$id – The $id field contains the value of the _id field in the referenced document.

$db – Optional.

Contains the name of the database where the referenced document resides.

Only some drivers support $db references.

https://docs.mongodb.com/manual/reference/database-references/#dbrefs

More sources to read about

1> https://docs.mongodb.com/manual/reference/database-references/

2>https://code.tutsplus.com/articles/an-introduction-to-mongoose-for-mongodb-and-nodejs–cms-29527