Skip to main content

Example of a lookup in MongoDB


This mini tutorial demonstrates a lookup in MongoDB, the equivalent of a "JOIN" in SQL, using Mongoose.

Code and example data is available on my Github page.

Data model

In this example we have two collections for the data of cooking recipes - one for the title and overview metadata, and one for the one or many component part(s) of a single recipe.

The data model looks like this:

datamodel-recipes-1.0.1

The collection recipeparts references the collection recipes via the recipe_id field.

The rationale behind this modeling is that the use cases indicate the data in the collection recipes is accessed far more frequently than that in the recipeparts collection.

Node.js/ Mongoose implementation

The model schemata might then be defined like this:

const mongoose = require('mongoose')

const ingredQtyModel = new mongoose.Schema({
amt: { type: String, required: true },
unit: { type: String },
})

const ingredModel = new mongoose.Schema({
name: { type: String },
qty: { type: ingredQtyModel },
})

const recipeModel = new mongoose.Schema({
title: { type: String, required: true },
})

const recipePartModel = new mongoose.Schema({
title: { type: String, required: true },
recipe_id: { type: mongoose.Types.ObjectId, ref: 'recipes' }, // <<== this is the lookup link
ingreds: [ ingredModel ],
method: [ String ]
})

const Recipes = mongoose.model('recipes', recipeModel)
const RecipeParts = mongoose.model('recipeParts', recipePartModel)

Note that the lookup linkage is effected in the recipePartModel (line 19) by specifying the ref to the parent 'recipes' model (line 24) for the attribute recipe_id of type ObjectId.

A minimal implementation on the command line might look like this:

const mongoose = require('mongoose')

const URI = `mongodb+srv://${MONGODB_USER}:${MONGODB_PASS}@cluster01.koazls1.mongodb.net/db1`

const main = async () => {
await mongoose.connect(URI)
const recipe = await Recipes.findOne({ title: { $regex: /^Warm salmon/ } })
const oid = new mongoose.Types.ObjectId(recipe?._id.toString())
const recipeParts = await RecipeParts.find({ recipe_id: oid }).populate('recipe_id')
console.log(JSON.stringify(recipeParts, null, 2))
}

main().catch(err => console.log(err))

with the .populate() method (line 74) effecting the lookup or join between the collections.

Demo

On my Github page there are two scripts which demonstrate how this join works.