Search code examples
node.jsmongodbexpressmongoosemongoose-populate

MongoDB and Mongoose One-to-many Relationship


I'm new at Mongoose. I have two collections => User and Task.

Each User can have multiple tasks but each Task can have only one User.

UserSchema:

const UserSchema = new Schema({
          name: {
            type: String, // type of the variable
            required: [true, "Please provide a name"], // this variable must be filled
          },
          tasks: [
            {
          type: mongoose.Schema.ObjectId,
          ref: "Task",
        },
      ],
    });

    

TaskSchema:

const TaskSchema = new Schema({
  title: {
    type: String, // type of the variable
    required: [true, "Please provide a title"], // this variable must be filled
  },
  user: {
    type: mongoose.Schema.ObjectId,
    required: true,
    ref: "User", // give reference to the user model
  },
});

The code below lists all Task data with their Users:

await Task.find().populate("user");

But when I list the User data, the task property comes empty:

await User.find().populate(tasks");

Create Task Body:

{
    "title": "Task 1",
    "user": "64afb6943c764b68ad9c1f61"
}

My question is when I add the new task, should I also add task id to the user tasks property on the MongoDB? Because I can't read the user's task in this way.


Solution

  • Yes. you should push() the new task to user.tasks array.

    const user = await User.findById('64afb6943c764b68ad9c1f61');
    
    const task = new Task({ title: 'Task 1', user });
    await task.save();
    
    user.tasks.push(task);
    await user.save();
    

    Complete working example:

    // @ts-nocheck
    import mongoose from 'mongoose';
    import util from 'util';
    import { config } from '../../config';
    
    mongoose.set('debug', true);
    console.log(mongoose.version);
    
    const UserSchema = new mongoose.Schema({
        name: String,
        tasks: [
            {
                type: mongoose.Schema.ObjectId,
                ref: 'Task',
            },
        ],
    });
    const User = mongoose.model('User', UserSchema);
    
    const TaskSchema = new mongoose.Schema({
        title: String,
        user: {
            type: mongoose.Schema.ObjectId,
            required: true,
            ref: 'User',
        },
    });
    
    const Task = mongoose.model('Task', TaskSchema);
    
    (async function main() {
        try {
            await mongoose.connect(config.MONGODB_URI);
            // seed
            const u = new User({ name: 'Nick' });
            await u.save();
    
            // create task
            const user = await User.findById(u._id);
            const task = new Task({ title: 'Task 1', user });
            await task.save();
            user.tasks.push(task);
            await user.save();
    
            // populate
            const users = await User.find().populate('tasks');
            console.log('users:', util.inspect(users, false, null));
            const tasks = await Task.find().populate('user');
            console.log('tasks: ', util.inspect(tasks, false, null));
        } catch (error) {
            console.error(error);
        } finally {
            await mongoose.connection.close();
        }
    })();
    

    Logs:

    users: [
      {
        _id: new ObjectId("64afbe6276adf1531b71117c"),
        name: 'Nick',
        tasks: [
          {
            _id: new ObjectId("64afbe6376adf1531b71117f"),
            title: 'Task 1',
            user: new ObjectId("64afbe6276adf1531b71117c"),
            __v: 0
          }
        ],
        __v: 1
      }
    ]
    Mongoose: tasks.find({}, {})
    Mongoose: users.find({ _id: { '$in': [ ObjectId("64afbe6276adf1531b71117c") ], [Symbol(mongoose#trustedSymbol)]: true }}, { skip: undefined, limit: undefined, perDocumentLimit: undefined })
    tasks:  [
      {
        _id: new ObjectId("64afbe6376adf1531b71117f"),
        title: 'Task 1',
        user: {
          _id: new ObjectId("64afbe6276adf1531b71117c"),
          name: 'Nick',
          tasks: [ new ObjectId("64afbe6376adf1531b71117f") ],
          __v: 1
        },
        __v: 0
      }
    ]