Malek Boubakri
Malek Boubakri

Reputation: 856

Populate none ref objects of a nested array

I'm working on a project that uses:

    "@nestjs/core": "^7.0.0",
    "@nestjs/mongoose": "^7.0.0",
    "mongoose": "^5.9.12",
    // ...
    "typescript": "^3.7.4",

With mongoose/mongoDB config:

      uri: MONGO_DB_URI,
      useUnifiedTopology: true,
      useNewUrlParser: true,
      useFindAndModify: false,
      useCreateIndex: true,

I'm trying to build a simple CRUD for this model:

export const ContactSchema = new mongoose.Schema(
  {
    source_id: { type: String, required: true },
    firstName: { type: String, trim: true },
    lastName: { type: String, trim: true },
    phones: [
      {
        number: {
          type: String,
          required: true,
          unique: true,
          validate: {
            validator: function(value) {
              const phoneNumber = parsePhoneNumberFromString(value)
              return phoneNumber && phoneNumber.isValid()
            },
          },
        },
        type: {
          type: String,
          default: function() {
            return parsePhoneNumberFromString(this.number).getType() || "N/A"
          },
        },
        code: {
          type: Number,
          default: function() {
            return parsePhoneNumberFromString(this.number).countryCallingCode || undefined
          },
        },
        national: {
          type: Number,
          default: function() {
            return parsePhoneNumberFromString(this.number).nationalNumber || undefined
          },
        },
      },
    ],
    email: { type: String, unique: true, required: true, lowercase: true, trim: true },
  },
  { timestamps: true },
)

ContactSchema.plugin(mongoosePaginate)

Like every CRUD app, I'm willing to have fildAll() & fildOne() routes that return the body of a given Contact with all his info including the list of its phone numbers. So I used:

  // ...
  async findAll(): Promise<Contact[]> {
    return this.contactModel.find()
    // then I add
    .populate('phones')
  }

  async findBySourceId(id: string): Promise<Contact> {
    return this.contactModel.findOne({ source_id: id })
    // then I add
    .populate('phones')
  }
  // ...

All info are well saved in the DB and there is no missing data (neither phones) and I'm sure that it works the beginning without even adding .poplate('x'), but that changed somewhere and it returns now unpopulated phone array.

Now It returns:

    {
        "_id": "5ebc22072e18637d84bcf6f0",
        "firstName": "Maher",
        "lastName": "Boubakri",
        "phones": [],
        "email": "[email protected]",
        // ...
    }

But, It should return:

    {
        "_id": "5ebc22072e18637d84bcf6f0",
        "firstName": "Maher",
        "lastName": "Boubakri",
        "phones": [
            {
                "_id": "5ebc22072e18637d8fd948f9",
                "number": "+21622123456",
                "code": 216,
                "type": "MOBILE",
                "national": 22123456,
            }
        ],
        "email": "[email protected]",
        // ...
    }

Note: It is clear that MongoDB generates _id for every phone object, but, it is not a ref Object.

Any idea will be so helpful,

Thank you.

Upvotes: 0

Views: 253

Answers (2)

Malek Boubakri
Malek Boubakri

Reputation: 856

Based on @Mohammed 's comment and answer, adding .lean() after updating mongoose fixed the problem.

// ...
  async findAll(): Promise<Contact[]> {
    return this.contactModel.find().lean()
  }

  async findBySourceId(id: string): Promise<Contact> {
    return this.contactModel.findOne({ source_id: id }).lean()
  }
// ...

Upvotes: 0

Mohammed Yousry
Mohammed Yousry

Reputation: 2184

populate is used to join two (or more) collections using the references

here you don't have any references, so you don't need it

just use find() without populate

Upvotes: 2

Related Questions