Поиск 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

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

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

Что такое category в req.query? Например, это ObjectId'660c892cb65f2f1f584144ca' в вашем документе?

jQueeny 07.04.2024 12:01

Да, но я пробовал найти и по названию, и по ObjectId, результат один и тот же

asd qwe 07.04.2024 13:49

Можете ли вы опубликовать свою схему продукта, потому что ваш запрос выглядит нормально. Возможно, проблема в вашем пропуске.

jQueeny 07.04.2024 15:50

Добавил схему. Продукты — это просто контейнер для всех продуктов.

asd qwe 07.04.2024 16:08

Если ваш запрос находит 1 документ, но ваш пропуск равен 2, вы получите пустой массив. Закомментируйте пропуск, чтобы убедиться, что ваш запрос находит то, что вы ожидаете.

jQueeny 07.04.2024 16:18

Он по-прежнему возвращает пустой массив :(

asd qwe 07.04.2024 16:35

Как вы реализуете поле category? Это вложенный документ унаследованной схемы? Опубликуйте схему, так как она выглядит так: ProductsSchema — это базовая схема.

jQueeny 07.04.2024 17:42

Вы разместили Category Schema, но это PhoneSchema, которое мне нужно увидеть. Тот, который определяет, что такое category. Я предполагаю, что PhoneSchema наследует от ProductsSchema.

jQueeny 07.04.2024 18:06
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
8
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

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

Но разве mongoose не добавляет поле id автоматически в свои схемы?

asd qwe 07.04.2024 17:57

Да, у мангуста есть, но вы спрашиваете здесь, так что это отдельная тема. Ваш category будет передан как строка в req.qery, но если это ObjectId, то mongoose обычно преобразует его в ObjectId для вас во время запроса. Поскольку вы используете наследование, оно, вероятно, не преобразуется в ObjectId, поэтому, выполнив new mongoose.Types.ObjectId(category), вы преобразуете запрос из строки в ObjectId. В качестве альтернативы вы можете просто использовать PhoneModel вместо ProductModel, если знаете, что будете запрашивать category.

jQueeny 07.04.2024 18:03

Да, я понял логику. Но, к сожалению, я все равно получаю пустой массив. В вопрос добавлена ​​схема телефона.

asd qwe 07.04.2024 22:26

Вы сделали new mongoose.Types.ObjectId(category) и удалили skip(), чтобы посмотреть, найдете ли вы хотя бы 1 документ?

jQueeny 07.04.2024 22:37

Я только что прочитал ваш PhoneSchema. Ваш запрос должен быть { 'category': new mongoose.Types.ObjectId(category) }. Я обновлю ответ. category будет то, что хранится в базе данных, а не category._id. _id не существует, пока populate не выполнится.

jQueeny 07.04.2024 22:43

Да, я сделал все, как вы советовали. Кстати, я кое-что протестировал. В этом массиве Products я добавил к объектам новое поле type. Теперь, когда я пытаюсь найти определенный объект по типу, передавая ObjectId этого type соответственно (я передал его в запрос категории), то все работает нормально и объект находится. Но как только я пытаюсь найти категорию (конечно, меняю ObjectId на соответствующий id категории), мне снова возвращается пустой массив. Я думаю, проблема в том, что он не может достичь вложенного поля _id в категории. Обновил код в квесте.

asd qwe 07.04.2024 22:45

О да, это работает. Еще раз спасибо ОГРОМНОЕ

asd qwe 07.04.2024 22:47

Другие вопросы по теме