In alcuni casi adottare un approccio relazionale in MongoDB si rivela essere la scelta giusta per mantenere gestibile il database.

Supponiamo di voler aggiungere un sistema di commenti ai post di un blog. Potremmo creare nello schema di un documento della collezione posts un campo comments e definirlo come array di documenti embedded.

Il salvataggio di un commento e il reperimento dei commenti di un post risultano essere immediati. Il problema sorge a lungo andare quando decidiamo di voler analizzare i commenti per fini statistici.

Dovremmo quindi effettuare una query per ottenere tutti i post, estrarre l'array dei commenti da ogni singolo documento e utilizzare la manipolazione degli array JavaScript per analizzare i dati. Ciò significa che per creare un ipotetico riassunto delle statistiche dei commenti occorrerebbe un tempo sempre maggiore man mano che vengono pubblicati nuovi post.

Invece se lo schema della collezione dei post (con Mongoose) è il seguente:

'use strict';

const mongoose  = require('mongoose');

const { Schema }  = mongoose;

const PostsSchema = new Schema({
    ID: Number,
    post_date: Date,
    post_content: String,
    post_title: String,
    post_excerpt: String,
    post_slug: String
},{collection: 'posts'});

module.exports = mongoose.model('posts', PostsSchema);

possiamo sfruttare un campo di tale schema per correlare questa collezione con la collezione dei commenti (comments). Nel nostro esempio useremo il campo ID.

'use strict';

const mongoose  = require('mongoose');

const { Schema }  = mongoose;

const CommentSchema = new Schema({
    post_id: Number,
    comment_date: Date,
    comment_text: String,
    comment_author: String
},{collection: 'comments'});

module.exports = mongoose.model('comments', CommentSchema);

post_id conterrà il valore del campo ID di ciascun post, permettendo così la correlazione tra le due collezioni.

Quindi in ExpressJS l'associazione tra singolo post e commenti ad esso correlati avverrà in questo modo:

'use strict';

const express = require('express');
const router = express.Router();
const posts = require('../models/posts');
const comments = require('../models/comments');


router.get('/:slug', async (req, res, next) => {
    const { slug } = req.params;
    try {
        const single = await posts.findOne({ post_slug: slug });
        const singleComments = await comments.find({ post_id: single.ID }).sort({ comment_date: -1});
        res.render('single', {
            title: `${single.post_title} | Blog`,
            post: single,
            comments: singleComments
        });
    } catch(err) {
        res.sendStatus(500);
    }
    
});

module.exports = router;

Si tratta di una soluzione che ci consente di evitare di avere una collezione con array di documenti embedded la cui profondità di annidamento non è prevedibile. Infatti se volessimo abilitare i commenti annidati in stile Facebook, ci ritroveremmo a dover effettuare query su array annidati, mentre con la soluzione relazionale dovremmo semplicemente modificare lo schema dei commenti aggiungendo un campo reply_to contenente l'Object ID del commento di riferimento.