@triggerfinger

Как из одной схемы сослаться на вторую?

Есть две модели (в двух файлах): Brand.js и Product.js

const brandSchema = new mongoose.Schema ({
  name: String,
  image: String
})


const productSchema = new mongoose.Schema ({
  name: String,
  image: String,
  brand: { тут обратится к brandSchema }
})


Возникло два вопроса: откуда я в productSchema вообще знаю к какому именно brand.name обращаться? Выходит, я должен заранее получить либо список всех доступных брендов (типо ГУИ в админке CMS), либо другим способом знак к какому документу обратиться? Например, поиск просто совпадений name

И второй вопрос, как это правильно оформить без дубликации кода (чтоб они были в отдельых файлах).
Я вообще ничего по populate не нахожу, а в документации я ответа не нашел.
  • Вопрос задан
  • 1006 просмотров
Решения вопроса 1
@Abcdefgk
const Schema = mongoose.Schema; //так просто удобнее

const brandSchema = new Schema ({
  name: String,
  image: String
});

const productSchema = new Schema ({
  name: String,
  image: String,
  brand: { type: Schema.Types.ObjectId, ref: 'Brand' } // этот ref ссылается на имя модели, которое будет ниже
});


var Brand = mongoose.model('Brand', brandSchema); // вот оно, это имя в казычках
var Product = mongoose.model('Product', productSchema);

Теперь во время сохранения документа с продуктом ему в поле brand надо передавать id брэнда, к которому он относиться.

var briony = new Brand({
  name: "Briony",
  image: ".../briony.jpg"
});
var shapka = new Product({
  name: "Shapka",
  image: "...../shapka.jpg",
  brand: briony // тут id брэнда этой шапки (как показал чувак в том ответе - и я проверял - mongoose сам сообразит именно id брэнда вписать по переменной briony, но можно и явно - briony._id)
});
briony.save();
shapka.save();

Только это бессмысленное использование populate. Его смысл заключается в том, чтобы не передавать в документ много информации о соотносимом с ним документом - когда этой информации там действительно много. А тут только две строчки: имя и ссылка на логотип.
Смысл могло бы иметь обратное действие. Добавляем в схему брэндов поле:
const brandSchema = new Schema ({
  name: String,
  image: String,
  products: [{ type: Schema.Types.ObjectId, ref: 'Product' }]
});

И сохранив в базу документ shapka, здесь же делаем push её айдишника в массив продуктов от Briony:
var briony = new Brand({
  name: "Briony",
  image: ".../briony.jpg"
});
briony.products.push(shapka._id);

Вот теперь в поле products документ с именем Briony будет иметь не массив больших объектов с названиями продуктов, их описанием, ценой и т.д., а массив только айдишников продуктов, к этому брэнду относящихся.
И наоборот. Если схема брэнда предполагает не только его имя и картинку, а и ещё какое-то описание, длинную историю и т.д., то это всё не надо вписывать в документ продукта, а вписать только id бренда, а всю эту подробную муть запрашивать во время запроса документа shapka с помощью как раз populate:
Product
  .findOne({ name: 'Shapka' })
  .populate('brand') // это означает "заселить", т.е. по айдишнику, вписанному в поле brand продукта, найти в коллекции брендов - нужный брэнд и вывалить сюда всю о нём информацию
  .exec ... // и т.д.

Или
Product
  .findOne({ name: 'Shapka' })
  .populate('brand', 'image')
  .exec ... // и т.д.

если от бренда нужна только его картинка нопремер.
(или только его имя - .populate('brand', 'name')

Как-то так.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы