简体   繁体   中英

Update a subdocument in mongoDB using mongoose

User Schema

import mongoose, { Schema, model } from 'mongoose';

const TodoSchema = new Schema({
    task: {
        type: String,
        required: [true, 'Task is required'],
    },
    date: {
        type: Date,
        default: Date.now,
    },
    tags: {
        type: [String],
    },
});

const UserSchema = new Schema({
    name: String,
    googleId: Number,
    date: { type: Date, default: Date.now },
    email: String,
    picture: String,
    todos: {
        type: [TodoSchema],
    },
});
  1. Query the user with (some) googleId
  2. Find the todo with (todo) _id embedded within todos array
  3. Update that todo properties and return the new todo.

My approach

const user = await User.findOne({ googleId });
const { todos } = user;

const idx = todos.findIndex((td) => td._id == todoId);

todos[idx].task = task;
todos[idx].tags = tags;

const { todos: updatedTodos } = await user.save();

Problem with my approach

My approach does work, but it doesn't seem to be an optimal solution as in the case of changing or adding more fields to the todo schema. While I did consider using spread operator, but that produced new todo id each time the todo is updated

Question

How should I do this using mongoose?

If you have a Schema for todos, this means that each todo has a unique id in MongoDB. You don't have to filter the todos, in step 2:

STEP 1:
const user = await User.findOne({ googleId });
const { todos } = user;

STEP 2: // don't do this
const idx = todos.findIndex((td) => td._id == todoId);

STEP 3:
todos[idx].task = task;
todos[idx].tags = tags;

STEP 4:
const { todos: updatedTodos } = await user.save();

Consider this:

  • You already have the todoId which you want to modify
  • Find if the user exists
  • Check if the todo belongs to the user
  • Use findByIdAndUpdate under mongoose

My suggestion:

const todoId = xxxxxxxxx

const user = await User.findOne({googleId})

const orderIdBelongsToUser = user.todos.includes(todoId)
// I'm assuming this is an array of orderIds, otherwise you can decide whether or not to do this check. 
// It seems pretty redundant, if you already have the todo id.

const newTodoObject = {
task: xxxx,
tags: xxxxx
}

if (orderIdBelongsToUser) {
const response = await Todo.findByIdAndUpdate(todoId, newTodoObject)
}

Hope I managed to help.

Reference: https://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM