mongoose find doesn't return any doc, while compass does

Viewed 811

Goal

Fetching products by category id from mongoDB 'products' collection using mongoose.find

Excpected and actual results

All the documents having the matching category should return, in the limit number, but I receive an empty array instead. I tried to query using mongodb's compass - it worked as expected. I even tried my code to find documents using id(worked), title(worked) and price(didn't work). Can't find the beginning of the problem root.

Code

Product schema and model:

const mongoose = require('mongoose');

const productSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
  },
  thumbnail: {
    type: String,
    required: true,
  },
  price: {
    type: Number,
    required: true,
  },
  category: {
    type: mongoose.Types.ObjectId,
    required: true,
  },
  rating: {
    type: Number,
    default: 0,
  },
  voters: {
    type: Number,
    default: 0,
  },
});

.
.
.

const Product = mongoose.model('product', productSchema);

module.exports = { Product, ... };

Resolver:

products: (_, { limit, category }) => {
      console.log(mongoose.Types.ObjectId('5ec120a9fc13ae248f000004')); // Works fine
      Product.find({ category: mongoose.Types.ObjectId(category) }) // Tried also as a simple string, still not working
        .limit(limit)
        .exec((err, products) => {
          if (err) console.log(err);
          console.log(products);
        });
      if (category) return Product.find({ category }).limit(limit);
      return Product.find({}).limit(limit);
    },

Result recorded in the console:

5ec120a9fc13ae248f000004
[]

Collection 'products' sample:

{
    "_id": {
        "$oid": "5ec129e55db26438fcdb9b01"
    },
    "title": "Ecolab - Lime - A - Way 4/4 L",
    "category": "5ec120a9fc13ae248f000004",
    "thumbnail": "https://source.unsplash.com/350x390/?Automotive",
    "price": "236.13",
    "rating": 878210,
    "voters": 2668388
},
{
    "_id": {
        "$oid": "5ec129e55db26438fcdb9b02"
    },
    "title": "Mushrooms - Black, Dried",
    "category": "5ec120a9fc13ae248f000001",
    "thumbnail": "https://source.unsplash.com/350x390/?Sports",
    "price": "439.85",
    "rating": 549879,
    "voters": 2375685
},
{
    "_id": {
        "$oid": "5ec129e55db26438fcdb9b03"
    },
    "title": "Dried Figs",
    "category": "5ec120a9fc13ae248f000004",
    "thumbnail": "https://source.unsplash.com/350x390/?Automotive",
    "price": "202.60",
    "rating": 925701,
    "voters": 2740499
}
1 Answers

TL;DR: You have to convert the data at the fields price and category in your database to Number and ObjectId

When you are querying data with Mongoose, make sure that the data types all match:

  1. The data types of the field you are querying matches with your schema

With some operation (like aggregation, where mongoose can not easily infer the types), mongoose will help converting it for you according to the schema, but not always. It's better to always convert the values by yourself to avoid surprises like this.

  1. The data types of the data stored in the database actually matches what you specify in your schema.

Your schema might have changed, make sure to migrate and convert the data accordingly. Since mongoose converts the values for you sometimes, if the stored data doesn't match the schema, it won't match what you try to query.

From your database output, we can infer that "price": "236.13" and "category": "5ec120a9fc13ae248f000004" are stored as Strings not Number and ObjectId as supposed to. We can see from "rating": 878210, and "_id": { "$oid": "5ec129e55db26438fcdb9b01" } how Number and ObjectId are represented.

Related