How to push an element to an array in a MongoDB document on Nest.js?

Viewed 1496

I feel extremely dumb making this question, but it's my first time working with Typescript in general and Nest.js in particular. I'm working with Nest, MongoDB (through Mongoose) and Express.js.

I have two models: User and Post. For this, the relevant one would be the User:

import * as Mongoose from 'mongoose';

export const UserSchema = new Mongoose.Schema(
  {
    username: { type: String, required: true },
    posts: { type: [Mongoose.SchemaTypes.ObjectId], ref: 'Post' },
    favs: { type: [Mongoose.SchemaTypes.ObjectId], ref: 'Post' },
  },
  {
    timestamps: true,
  },
);

I'm making an API for a Twitter-like app, in which an user can create posts and add them to Favorites. I'm following tutorials, as one does when new to a technology, but I'm struggling to see how to push a new fav to the user's favs. Here's the User controller, so far:

import {
  Controller,
  Get,
  Req,
  Res,
  HttpStatus,
  Put,
  NotFoundException,
  Param,
} from '@nestjs/common';
import { UserService } from './user.service';
import { Request, Response } from 'express';
import { CreateUserDTO } from './dto/create-user.dto';

@Controller('user')
export class UserController {
  constructor(private userService: UserService) {}

  //fetch an user
  @Get('userfavs/:userID')
  async getCustomer(@Res() res: Response, @Param('userID') userID: string) {
    const user = await this.userService.getUser(userID);

    if (!user) throw new NotFoundException('This user does not exist!');

    return res.status(HttpStatus.OK).json({
      username: user.username,

      favs: user.favs,
    });
  }

  @Put('addfav/:favID')
  async updateUser(
    @Req() req: Request,
    @Res() res: Response,
    @Param('favID') favID: string,
    @Body() createUserDTO: CreateUserDTO,
  ) {
    const user = await this.userService.updateUser(req.user._id, createUserDTO);
    if (!user) throw new NotFoundException('This user does not exist!');
    return res.status(HttpStatus.OK).json({
      message: 'Fav added successfully!',
    });
  }
}

And the service:

import { Injectable } from '@nestjs/common';
import { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { User } from './interfaces/user.interface';
import { CreateUserDTO } from './dto/create-user.dto';

@Injectable()
export class UserService {
  //creates Mongoose model for the User
  constructor(@InjectModel('User') private readonly userModel: Model<User>) {}

  //fetch a specific user - this will be useful to check favs
  async getUser(userID: string): Promise<User> {
    const user = await this.userModel
      .findById(userID)
      .populate('favs')
      .exec();
    return user;
  }

  //edit an specific user
  async updateUser(
    userID: string,
    createUserDTO: CreateUserDTO,
  ): Promise<User> {
    const updatedUser = await this.userModel.findByIdAndUpdate(
      userID,
      createUserDTO,
      { new: true },
    );
    return updatedUser;
  }
}

In Node.js I would have done like:

User.findByIdAndUpdate(req.user._id, {
        $push: { favs: favId },
      })

But in Nest, the DTO is throwing me for a loop.

1 Answers

With NestJS, you can fetch your document from Mongo with a find operation (find, findById, findOne, etc). Then, modify that object, and save. You can pass your favId to your service from your controller instead of the DTO. In your service:

async updateUser(
  userID: string,
  favId: string
): Promise < User > {
  const user = await this.userModel.findById(userID).exec();
  if (!user) {
    throw new NotFoundException();
  }

  user.favs.push(favId);
  return user.save();
}

Related