Home > database >  How to find a user ref in an array of ids within an Mongo DB Collection?
How to find a user ref in an array of ids within an Mongo DB Collection?

Time:10-25

I have an app and when the user signs in, I want it to retrieve the FirmDoc based on the user id passed through my currentUser middleware (req.currentUser.id). That user id is a mongoose.Types.ObjectID (corresponds to _id in mongoose). The FirmDoc has a users property that is an array of ObjectID strings. I am new to mongoose so there may be some errors below but I ultimately want to know how to pull the FirmDoc per a given user id from the users property.

firm.ts:

import mongoose from 'mongoose';
import { FirmStatus } from "@mavata/common";

export { FirmStatus };

interface FirmAttrs {
  domain: string;
  name: string;
  type?: string;
}

interface FirmModel extends mongoose.Model<FirmDoc> {
  build(attrs: FirmAttrs): FirmDoc;
  deleteById(id: string): FirmDoc;
}

interface FirmDoc extends mongoose.Document {
  domain: string;
  status: FirmStatus;
  name: string;
  type: string;
  users: string[];
  companies: string[];
}

const firmSchema = new mongoose.Schema({
  domain: {
    type: String,
    required: true
  },
  name: {
    type: String,
    required: true
  },
  status: {
    type: String,
    enum: Object.values(FirmStatus),
    default: FirmStatus.Created,
    required: true,
  },
  type: {
    type: String,
    default: '',
    required: false
  },
  users: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'User',
    default: [],
    required: true
  }],
  companies: [{
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Company',
    default: [],
    required: true
  }]
},
{
  toJSON: {
    transform(doc, ret) {
      ret.id = ret._id;     // rename _id property to id
      delete ret._id;       // delete the _id property off the object
      delete ret.__v;       // delete useless property
    }
  }
});

firmSchema.pre('save', async function(done) {

  console.log('firm saved of type ', this.type);
  done();
});

firmSchema.statics.build = (attrs: FirmAttrs) => {
  return new Firm(attrs);
};

firmSchema.statics.deleteById = async (id: string) => {
  return await Firm.deleteOne({ _id: new mongoose.Types.ObjectId(id)});
};

const Firm = mongoose.model<FirmDoc, FirmModel>('Firm', firmSchema);

export { Firm };

index.ts (router):

import express, { Request, Response } from "express";
import { requireAuth } from "@mavata/common";
import { Firm } from "../models/firm";

const router = express.Router();

router.get("/api/firm", requireAuth, async (req: Request, res: Response) => {
  const firms = await Firm.find({users: req.currentUser!.id}, (err: any, docs: any) => {
    if (err) {
      console.log(err);
    } else {
      console.log(docs);
    }
  })

  res.send(firms);
});

export { router as indexFirmRouter };

CodePudding user response:

There are multiple ways to handle this with Mongoose, but as far as I can tell from this snippet, your current logic should work. You are querying all 'Firm' documents where the users field contains 'req.currentUser.id'.

Try hard-coding a user ID instead of passing the req just for debugging purposes. If that works, then obviously the dynamic variable is not passing correctly. Perhaps you are missing a 'req.params', 'req.headers', 'req.body' when pulling the user id? Depending on your authorization config.

Alternative...

See the mongoose docs regarding populate() and virtuals. Mongoose allows for creating a 'virtual' reference from one model to another. In your case, create a virtual on User pointing to Firm.

// user.ts

userSchema(
  {...},
  {toJSON: {virtuals: true}, toObject: {virtuals: true}}
);

userSchema.virtual('firm', {
  ref: 'Firm',
  localField: '_id',
  foreignField: 'users',
  justOne: false,
});

Then in your user route, you can pass the user id and reverse populate the Firm doc.

router.get("/api/user", requireAuth, async (req: Request, res: Response) => {

  const userId = req.currentUser.id
  const user = await User.findById(userId).populate('firm').exec();

    if (!user) {
      console.log('User not found');
    } else {
      console.log(user);
    }
  }

  res.status(200).json(user);
});
  • Related