How do i use populate with a custom ObjectId of a type: String?

Viewed 185

I have a firebase project that I use for authentication. I also save additional user info in the mongodb and assign the uid of the firebase user to the _id field of the user model. In order to do that, I have to set the type of ObjectId to a String, otherwise mongodb doesn't let me save the user as the firebase uid is a bit longer than ObjectId. It seems that the ObjectId is of type:String, I can no longer use populate on my queries.

Here are the models:

const UserSchema = new Schema({
  _id: String,
  name: String,
});

const SurveySchema = new Schema({
  user_id: { type: String, ref: "users" },
  category: String,
});

I tried to set user_id: { type: mongoose.ObjectId, ref: "users" }, but I just get an error(Cast to ObjectId failed) instead of undefined.

Here is the controller where I use populate:

const SurveyList = await Survey.find(
  {
    user_id: req.currentUser.uid,
    category: "example",
  },
  "_id user_id category createdAt updatedAt"
).populate("user_id");

I checked, the ids match, but I still get undefined. The populate used to work when I had regular mongo ObjectIds, but after I started using firebase it no longer works.

The response I get is like this:

"SurveyList": [
    {
      "status": "1",
      "_id": "60abcd94e9cddb2ba44f24b4",
      "user_id": null,
      "category": "Health",
      "createdAt": "2021-05-24T16:00:20.688Z",
      "updatedAt": "2021-05-24T16:00:20.688Z"
    }
  ]

Please note that the error began occurring only after I changed _id to type:String. It used to work fine when it was a default mongoose.ObjectId

1 Answers

You cannot populate the field that you're using to store the reference to the user's id. That field is the one that will be used in order to populate the virtual field. If what you want to do is having a virtual field SurveyList[i].user that retrieves the user's data in each SurveyList entry, you need to create it:

SurveySchema.virtual("user", {
  ref: "users",
  localField: "user_id",
  foreignField: "_id",
  justOne: true,
});

Then you'll need to populate the virtual field:

const SurveyList = await Survey.find(
  {
    user_id: req.currentUser.uid,
    category: "example",
  },
  "_id user_id user category createdAt updatedAt"
).populate("user");
Related