Поиск Mongoose по вложенному объекту модели

У меня есть какая-то логика фильтрации продуктов.

В модели «Продукты» я ищу определенные продукты по параметрам запроса, которые помещаются в массив настроек (queryConditions), если такая фильтрация существует.

Это один из объектов, существующих в модели «Продукты».

{
    "products": [
        {
            "_id": "6612fee192f83be6c8f1f14a",
            "name": "Iphone 15",
            "__t": "Phones",
            "price": "105990",
            "color": "Белый",
            "memory": "128",
            "screen": "2480 x 1080",
            "fps": "240",
            "sim": "eSim",
            "preview": "3e26f117-e925-4303-adb5-930874e7ea21.png",
            "images": [
                "3db588ef-63f6-4596-8284-f02f4e465765.png",
                "e9437348-eb56-4537-8c13-cbbb697bcc41.png"
            ],
            "category": {
                "_id": "6612b3c9a56d07ad6a21e332",
                "name": "Телефоны",
                "preview": "phones.png"
            },
            "type": "6612b4a9a56d07ad6a21e384",
            "count": 1,
            "createdAt": "2024-04-07T20:15:29.009Z",
            "updatedAt": "2024-04-07T20:15:29.009Z",
            "__v": 0
        }
    ],
    "count": 1
}

Логика фильтрации

import { mongoose } from 'mongoose'
import ProductsModel from '../models/ProductsModel.js'

class ProductsController {
    async getAll(req, res) {
        // Filters
        const { search, color, date, category, price } = req.query
        const limit = 10
        const page = Number(req.query.page) || 1
        const skip = (page - 1) * limit

        const queryConditions = []
        const sortConditions = []

        if (search) {
            queryConditions.push({ name: new RegExp(search, 'i') })
        }

        if (color) {
            queryConditions.push({ color: color })
        }

        if (category) {
            // queryConditions.push({ type: new mongoose.Types.ObjectId(category) })
            queryConditions.push({ 'category._id': new mongoose.Types.ObjectId(category) })
        }

        console.info(category)

        if (price === 'up') {
            sortConditions.push(['price', 1])
        }

        if (price === 'down') {
            sortConditions.push(['price', -1])
        }

        if (date === 'old') {
            sortConditions.push(['createdAt', 1])
        }

        if (date === 'new') {
            sortConditions.push(['createdAt', -1])
        }

        const products = await ProductsModel.find()
            .populate({ path: 'category', select: ['name', 'preview'] })
            .and(queryConditions.length > 0 ? queryConditions : [{}])
            .sort(sortConditions)
        // .skip(skip)
        // .limit(limit)

        const count = await ProductsModel.find()
            .and(queryConditions.length > 0 ? queryConditions : [{}])
            .countDocuments()

        return res.json({ products, count })
    }

export default new ProductsController()

Схема продуктов

import { Schema, model } from 'mongoose'

export const productsDiscriminatorKey = 'productKind'

const ProductsSchema = new Schema(
    {
        name: { type: String },
    },
    { productsDiscriminatorKey, timestamps: true }
)

export default model('Products', ProductsSchema)

Схема категории

import { Schema, model } from 'mongoose'

const CategoryModel = new Schema(
    {
        name: {
            type: String,
            required: true,
            unique: true,
        },
        preview: {
            type: String,
            required: true,
        },
        types: [{ type: Object }],
    },
    { timestamps: true }
)

export default new model('Category', CategoryModel)

Схема телефона

import mongoose, { Schema } from 'mongoose'

import ProductsModel, { productsDiscriminatorKey } from './ProductsModel.js'

const PhoneSchema = new Schema(
    {
        name: { type: String, required: true },
        price: { type: String, required: true },
        color: { type: String, required: true },
        memory: { type: String, required: true },
        screen: { type: String, required: true },
        fps: { type: String, required: true },
        sim: { type: String, required: true },
        preview: { type: String, required: true },
        images: [{ type: String, required: true }],
        category: {
            type: mongoose.Schema.ObjectId,
            ref: 'Category',
        },
        type: {
            type: mongoose.Schema.ObjectId,
            ref: 'Type',
        },
        count: { type: Number },
    },
    { productsDiscriminatorKey }
)

const PhoneModel = ProductsModel.discriminator('Phones', PhoneSchema)
export default PhoneModel

Фильтрация по имени и цвету поиска работает корректно, но когда я пытаюсь получить объект, категория которого равна категории, которую я передаю через запрос, я получаю пустой массив.

Собственно, вопрос в том, как правильно реализовать поиск объекта вложенной категории и получить объект, идентификатор категории которого соответствует идентификатору, который я передаю через запрос.

🤔 А знаете ли вы, что...
JavaScript можно использовать для создания ботов и автоматизации задач в браузерах с помощью Puppeteer.


1
61
1

Ответ:

Решено

Скорее всего, для вашего параметра запроса category._id не существует Приведения запросов. Вы можете преодолеть это, создав новый экземпляр mongoose.Types.ObjectId следующим образом:

if (category){
   queryConditions.push({ 'category': new mongoose.Types.ObjectId(category) })
}