введение
Вслед за предыдущей статьей»Koa2+MongoDB+JWT实战--Restful API最佳实践», я получил отзывы от многих мелких партнеров, выражающих свою обеспокоенность по поводуmongooseЯ мало в этом разбираюсь, немного сложно начать, а официальные документы в основном на английском (на душе у ребенка горько, но ребенок не говорит).
Чтобы ваши друзья могли быстро приступить к работе и углубить ваше понимание мангуста, я специально организовал некоторые базовые знания о мангусте в сочетании с предыдущими проектами, которые очень полезны для реального боя. Я считаю, что прочитав эту статью, она обязательно поможет вам быстро начать работу и понять, как использовать mongoose.
В мангусте по-прежнему задействовано множество концепций и модулей, которые обычно включают следующее:
Эта статья не будет подробно объяснять один за другим, а в основном описывает несколько модулей, которые более важны в реальном бою:模式(schemas),模式类型(SchemaTypes),连接(Connections),模型(Models)а также联表(Populate).
схемы
определите свою схему
Mongooseвсе начинается сSchema. Каждая схема сопоставляется с коллекцией MongoDB (collection) и форма, определяющая документы в коллекции.
const mongoose = require("mongoose");
const { Schema, model } = mongoose;
const userSchema = new Schema(
{
__v: { type: Number, select: false },
name: { type: String, required: true },
password: { type: String, required: true, select: false },
avatar_url: { type: String },
gender: {
type: String,
enum: ["male", "female"],
default: "male",
required: true
},
headline: { type: String },
},
{ timestamps: true }
);
module.exports = model("User", userSchema);
здесь
__vдаversionKey. versionKey — это свойство, созданное mongoose при первом создании каждого документа. Содержит внутренние версии документации. Это свойство документа настраивается. По умолчанию__v. Если номер версии не требуется, добавьте его в схему{ versionKey: false}Вот и все.
Создать модель
Используя наше определение схемы, нам нужно преобразовать нашуuserSchemaПреобразуйте в модель, которую мы можем использовать. то естьmongoose.model(modelName, schema). То есть в приведенном выше коде:
module.exports = model("User", userSchema);
опции
Схемы имеют несколько настраиваемых параметров, которые можно передать непосредственно конструктору или задать:
new Schema({..}, options);
// or
var schema = new Schema({..});
schema.set(option, value);
Доступные Варианты:
autoIndexbufferCommandscappedcollectionid_idminimizereadshardKeystricttoJSONtoObjecttypeKeyvalidateBeforeSaveversionKeyskipVersioningtimestamps
Здесь я просто перечисляю часто используемые элементы конфигурации, полные элементы конфигурации можно посмотреть в официальной документацииhttps://mongoosejs.com/docs/guide.html#options.
Здесь я в основном говорю оversionKeyа такжеtimestamps:
-
versionKey(упомянутый выше) автоматически устанавливается Mongoose при создании файла. Это значение содержит внутренний номер версии файла. versionKey — это строка, представляющая имя свойства номера версии, значение по умолчанию —__v - если установлено
timestampsвариант, мангуст автоматически добавит его в вашу схемуcreatedAtа такжеupdatedAtполе, тип которогоDate.
На данный момент основное введение завершеноSchema, смотри дальшеSchemaTypes
Типы схем
SchemaTypesВыберите значения по умолчанию для запросов и других значений пути обработки по умолчанию, проверок, геттеров, сеттеров, полей и специальных символов для строк и чисел. Допустимые типы схемы в мангусте:
StringNumberDateBufferBooleanMixedObjectIdArrayDecimal128Map
См. простой пример:
const answerSchema = new Schema(
{
__v: { type: Number, select: false },
content: { type: String, required: true },
answerer: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
select: false
},
questionId: { type: String, required: true },
voteCount: { type: Number, required: true, default: 0 }
},
{ timestamps: true }
);
Все типы схем
-
required: логическое значение или функция, если оно истинно, добавьте требуемую проверку для этого свойства. -
default: Любой тип или функция, которая устанавливает значение по умолчанию для пути. Если значение является функцией, возвращаемое значение функции используется как значение по умолчанию. -
select: boolean указывает значение по умолчанию для запросаprojections -
validate: функция для добавления функции проверки к свойству. -
get: функция, использованиеObject.defineProperty()Определить пользовательский геттер -
set: функция, использованиеObject.defineProperty()Определить пользовательские сеттеры -
alias: строка, только истинаmongoose>=4.10.0эффективный. Определяет виртуальное свойство с заданным именем, которое может получить/установить этот путь
показатель
Вы можете объявить индексы MongoDB с опцией типа схемы.
-
index: Boolean, определить ли индекс в свойстве. -
unique: Boolean, определить ли уникальный индекс в свойстве. -
sparse: логическое значение, определяет ли разреженный индекс в свойстве.
var schema2 = new Schema({
test: {
type: String,
index: true,
unique: true // 如果指定`unique`为true,则为唯一索引
}
});
нить
-
lowercase: boolean, вызывать ли это значение перед сохранениемtoLowerCase() -
uppercase: boolean, вызывать ли это значение перед сохранениемtoUpperCase() -
trim: boolean, вызывать ли это значение перед сохранениемtrim() -
match: Regular, создает валидатор, который проверяет, соответствует ли значение заданному регулярному выражению. -
enum: массив, создает валидатор, который проверяет, является ли значение элементом в данном массиве
количество
-
min: число, создает валидатор, который проверяет, что значение больше или равно заданному минимальному значению. -
max: число, создает валидатор, который проверяет, что значение меньше или равно заданному максимальному значению.
Дата
-
min: Date -
max: Date
В настоящее время введеноSchematype, Давайте посмотрим наConnections.
Соединения
мы можем использоватьmongoose.connect()способ подключения к MongoDB.
mongoose.connect('mongodb://localhost:27017/myapp');
Это соединение работает локальноmyappМинимальное значение базы данных (27017). Если соединение не удалось, попробуйте использовать127.0.0.1заменятьlocalhost.
Конечно, вы можете указать больше параметров в uri:
mongoose.connect('mongodb://username:password@host:port/database?options...');
Кэш действий
Это означает, что мы можем использовать модели, не дожидаясь успешного установления соединения, и mongoose сначала будет кэшировать операции с моделями.
let TestModel = mongoose.model('Test', new Schema({ name: String }));
// 连接成功前操作会被挂起
TestModel.findOne(function(error, result) { /* ... */ });
setTimeout(function() {
mongoose.connect('mongodb://localhost/myapp');
}, 60000);
Если вы хотите отключить кеш, вы можете изменитьbufferCommandsконфигурации или глобально отключить bufferCommands
mongoose.set('bufferCommands', false);
опции
Метод подключения также принимает объект параметров:
mongoose.connect(uri, options);
Здесь я перечисляю несколько опций, которые более важны в повседневном использовании, смотрите полные варианты подключенияздесь
-
bufferCommands: это специальная опция в мангусте (не передается драйверу MongoDB), которая отключает缓冲机制. -
user/pass: Имя пользователя и пароль для аутентификации. Это специальные параметры в мангусте, они могут быть эквивалентны параметрам в драйвере MongoDB.auth.userа такжеauth.passwordопции. -
dbName: указывает, к какой базе данных подключаться, и переопределяет любую базу данных в строке подключения. -
useNewUrlParser: Базовая MongoDB устарела от текущего синтаксического анализатора строки подключения. Поскольку это критическое изменение, был добавлен флаг useNewUrlParser, позволяющий пользователю возвращать старый синтаксический анализатор в новый синтаксический анализатор, если пользователь сталкивается с ошибкой. -
poolSize: максимальное количество сокетов, которые драйвер MongoDB сохранит для этого соединения. По умолчанию poolSize равен 5. -
useUnifiedTopology: по умолчаниюfalse. Установите значение true, чтобы включить новый механизм управления соединениями с помощью драйвера MongoDB. Вы должны установить для этого параметра значение true, если редкие обстоятельства не мешают вам поддерживать стабильное соединение.
Пример:
const options = {
useNewUrlParser: true,
useUnifiedTopology: true,
autoIndex: false, // 不创建索引
reconnectTries: Number.MAX_VALUE, // 总是尝试重新连接
reconnectInterval: 500, // 每500ms重新连接一次
poolSize: 10, // 维护最多10个socket连接
// 如果没有连接立即返回错误,而不是等待重新连接
bufferMaxEntries: 0,
connectTimeoutMS: 10000, // 10s后放弃重新连接
socketTimeoutMS: 45000, // 在45s不活跃后关闭sockets
family: 4 // 用IPv4, 跳过IPv6
};
mongoose.connect(uri, options);
Перезвоните
connect()Функция также принимает параметр обратного вызова, который возвращает обещание.
mongoose.connect(uri, options, function(error) {
// 检查错误,初始化连接。回调没有第二个参数。
});
// 或者用promise
mongoose.connect(uri, options).then(
() => { /** ready to use. The `mongoose.connect()` promise resolves to undefined. */ },
err => { /** handle initial connection error */ }
);
законченныйConnections, давайте посмотрим на ключевой моментModels
Модели
ModelsОтSchemaСкомпилированный конструктор. Их экземпляры представляют собой данные, которые можно сохранить и прочитать из базы данных.documents. Все операции по созданию и чтению документов из базы данных выполняются черезmodelнепрерывный.
const mongoose = require("mongoose");
const { Schema, model } = mongoose;
const answerSchema = new Schema(
{
__v: { type: Number, select: false },
content: { type: String, required: true },
},
{ timestamps: true }
);
module.exports = model("Answer", answerSchema);
После определения модели вы можете выполнять некоторые добавления, удаления, изменения и операции поиска.
Создайте
еслиEntity,использоватьsaveметод; если этоModel,использоватьcreateметод илиinsertManyметод.
// save([options], [options.safe], [options.validateBeforeSave], [fn])
let Person = mongoose.model("User", userSchema);
let person1 = new Person({ name: '森林' });
person1.save()
// 使用save()方法,需要先实例化为文档,再使用save()方法保存文档。而create()方法,则直接在模型Model上操作,并且可以同时新增多个文档
// Model.create(doc(s), [callback])
Person.create({ name: '森林' }, callback)
// Model.insertMany(doc(s), [options], [callback])
Person.insertMany([{ name: '森林' }, { name: '之晨' }], function(err, docs) {
})
Сказав это, давайте сначала добавим описание трех концепций в мангусте:schema,modelа такжеentity:
-
schema: Скелет модели базы данных, хранящийся в виде файла, без возможности работы с базой данных. -
model: модель, созданная публикацией схемы, пара операций базы данных с абстрактными свойствами и поведением. -
entity: Объект, созданный Моделью, чьи операции также влияют на базу данных.
Пожалуйста, имейте в виду связь между схемой, моделью и сущностью:
Schema生成Model,Model创造Entity, Model и Entity могут влиять на операции базы данных, но Model более функциональна, чем Entity.
Запрос
Поиск документов упрощается с Mongoosecha, который поддерживает расширенный синтаксис запросов MongoDB. включатьfind,findById,findOneЖдать.
find()
Первый параметр представляет собой условие запроса, второй параметр используется для управления возвращаемыми полями, третий параметр используется для настройки параметров запроса, а четвертый параметр — это функция обратного вызова.Форма функции обратного вызова:function(err,docs){}
Model.find(conditions, [projection], [options], [callback])
Давайте по очереди рассмотрим применение каждого параметра find() в реальной сцене:
-
conditions- найти все
Model.find({})- Найти точное
Model.find({name:'森林'})- использовать оператор
Операторы, связанные с контрастом
символ описывать $eq равно указанному значению $ne не равно указанному значению $gt больше указанного значения $gte больше или равно указанному значению $lt меньше указанного значения $lte меньше или равно указанному значению $in соответствует любому из значений, указанных в массиве запроса $nin не соответствует ни одному из значений, указанных в массиве запроса Model.find({ age: { $in: [18, 24]} })вернуть
ageполе равно18или24всех документов.Логические операторы корреляции
символ описывать $and Все условия, указанные в массиве, выполнены $nor Не выполняются все условия, указанные в массиве $or выполняется одно из условий, указанных в массиве $not Отменить запрос, возвращая документы, которые не соответствуют указанным критериям. // 返回 age 字段大于 24 或者 age 字段不存在的文档 Model.find( { age: { $not: { $lte: 24 }}})Операторы, связанные с полем
символ описывать $exists соответствует документам, в которых существует указанное поле $type Возвращает документы, поля которых имеют указанный тип поиск поля массива
символ описывать $all Соответствует полю массива, содержащему все условия, указанные в массиве запроса. $elemMatch Соответствует значению в поле массива, которое удовлетворяет всем условиям, указанным в $elemMatch. $size Соответствует документам, длина поля массива которых равна указанному размеру // 使用 $all 查找同时存在 18 和 20 的 document Model.find({ age: { $all: [ 18, 20 ] } });
-
projectionУкажите, что включить или исключить
documentполя (также называемые запросами)投影»), должны быть указаны одновременно включать или исключать одновременно, нельзя смешивать,_idКроме.В мангусте есть два способа указать:
字符串指定а также对象形式指定.При указании строки добавьте знак - перед исключенным полем и напишите только имя поля.
Model.find({},'age'); Model.find({},'-name');Если указано в форме объекта,
1содержит,0исключено.Model.find({}, { age: 1 }); Model.find({}, { name: 0 }); -
options// 三种方式实现 Model.find(filter,null,options) Model.find(filter).setOptions(options) Model.find(filter).<option>(xxx)опции опции см. официальную документациюQuery.prototype.setOptions().
Здесь мы перечислим только наиболее часто используемые:
-
sort: Сортировка по заданному полю.Значения могут быть asc, desc, по возрастанию, по убыванию, 1 и -1. -
limit: указывает максимальное количество возвращаемых результатов -
skip: указать количество документов для пропуска -
lean: возвращает обычный объект js, а неMongoose Documents. Данные, возвращаемые на фронтенд без специальной обработки мангустом, рекомендуется конвертировать в обычные js-объекты с помощью этого метода.
// sort 两种方式指定排序 Model.find().sort('age -name'); // 字符串有 - 代表 descending 降序 Model.find().sort({age:'asc', name:-1});sortа такжеlimitПри одновременном использовании порядок вызовов не важен, возвращаемые данные сначала сортируются, а затем ограничиваются по количеству.// 效果一样 Model.find().limit(2).sort('age'); Model.find().sort('age').limit(2); -
-
callbackВсе входящие в Mongoose
callbackзапрос, форматcallback(error, result)эта форма. Если есть ошибка, ошибка — это сообщение об ошибке, а результат — null; если запрос выполнен успешно, ошибка — null, а результат — результат запроса. Структура результата запроса зависит от метода запроса.find()Результатом запроса метода является массив. Даже если содержимое не запрашивается, он вернет [] пустой массив.
findById
Model.findById(id,[projection],[options],[callback])
Model.findById(id)эквивалентноModel.findOne({ _id: id }).
Взгляните на официальнуюfindOneа такжеfindByIdСравнение:
Разница в том, что идентификатор обрабатывается как
undefinedситуация на тот момент.findOne({ _id: undefined })эквивалентноfindOne({}), возвращает любую часть данных. а такжеfindById(undefined)эквивалентноfindOne({ _id: null }),вернутьnull.
результат поиска:
- Формат возвращаемых данных
{}форма предмета. - идентификатор
undefinedилиnull, возвращается результатnull. - Если нет данных, удовлетворяющих условиям запроса, возвращается результат
null.
findOne
Этот метод возвращает первый из всех найденных экземпляров
Model.findOne(conditions, [projection], [options], [callback])
Если условие запроса_id, рекомендуется использоватьfindById().
результат поиска:
- Формат возвращаемых данных
{}форма предмета. - При наличии нескольких данных, соответствующих условиям запроса, возвращается только первый из них.
- Условия запроса: {}, null или undefined, и будет возвращена любая часть данных.
- Нет данных, соответствующих условиям запроса, и результат возвращает null.
возобновить
每个模型都有自己的更新方法,用于修改数据库中的文档,不将它们返回到您的应用程序。 Обычно используетсяfindOneAndUpdate(),findByIdAndUpdate(),update(),updateMany()Ждать.
findOneAndUpdate()
Model.findOneAndUpdate(filter, update, [options], [callback])
-
filterоператор запроса и
find()Такой же.фильтр
{}, обновляются только первые данные. -
update{operator: { field: value, ... }, ... }Необходимо использовать оператор обновления. Если нет оператора или оператор не
updateоператор, форма рассматривается как$setоперации (специфические для мангуста)Операторы, связанные с полем
символ описывать $set установить значение поля $currentDate Установите значение поля на текущее время, которое может быть Dateили формат метки времени.$min Обновлять, только если указанное значение меньше текущего значения поля $max Обновлять, только если указанное значение больше, чем текущее значение поля $inc Увеличить значение поля 指定数量,指定数量Может быть отрицательным, представляя уменьшение.$mul Умножает значение поля на указанную сумму $unset Удаляет указанное поле, а значение в массиве после удаления меняется на null. Операторы, связанные с полем массива
символ описывать $ Действует как заполнитель для первого элемента в поле массива, который соответствует критериям запроса. {operator:{ "arrayField.$" : value }}$addToSet Добавьте ранее несуществующий элемент на поле массива { $addToSet: {arrayField: value, ... }}, Значение представляет собой массив с$eachиспользуется в комбинации.$push Добавить элемент в конец поля массива { $push: { arrayField: value, ... } }, когда значение является массивом, его можно использовать с$eachмодификаторы, используемые в комбинации$pop Удалить первый или последний элемент в поле массива { $pop: {arrayField: -1(first) / 1(last), ... } }$pull Удалить все элементы в поле массива, соответствующие критериям запроса { $pull: {arrayField: value / condition, ... } }$pullAll Удалить все совпадающие значения из массива { $pullAll: { arrayField: [value1, value2 ... ], ... } }модификатор
символ описывать $each ретушь $pushа также$addToSetоператор для добавления нескольких элементов в поле массива.$position ретушь $pushоператор для указания позиции в массиве добавляемого элемента.$slice ретушь $pushоператор для ограничения размера обновляемого массива.$sort ретушь $pushоператор для изменения порядка элементов в поле массива.Порядок выполнения модификаторов (независимо от порядка их определения):
- Добавьте элемент в указанную позицию, чтобы обновить поле массива
- Сортировать по заданным правилам
- ограничить размер массива
- массив хранения
-
options- lean: true возвращает простые объекты js вместо
Mongoose Documents. - новое: логическое,
trueвозвращает обновленные данные,false(По умолчанию) Возвращает данные до обновления. - fields/select: указывает возвращаемые поля.
- sort: если условие запроса находит несколько документов, установите порядок сортировки, чтобы выбрать, какой документ обновлять.
- maxTimeMS: установите ограничение по времени для запроса.
- upsert: boolean, создать объект, если он не существует. По умолчанию
false. - omitUndefined: логическое значение, если оно
true, удалите значение перед обновлениемundefinedхарактеристики. - rawResult: если
true, возвращается собственный результат из MongoDB.
- lean: true возвращает простые объекты js вместо
-
callback- данные не найдены
null - Если обновление прошло успешно, верните данные до обновления (
{}форма) -
optionsиз{new:true}, обновление успешно возвращает обновленные данные ({}форма) - Условие запроса отсутствует, т.е.
filterЕсли он пуст, обновите первые данные
- данные не найдены
findByIdAndUpdate()
Model.findByIdAndUpdate(id, update, options, callback)
Model.findByIdAndUpdate(id, update)эквивалентноModel.findOneAndUpdate({ _id: id }, update).
результат запроса результата:
- Формат возвращаемых данных
{}форма предмета. - идентификатор
undefinedилиnull, возвращается результатnull. - Если нет данных, удовлетворяющих условиям запроса, возвращается результат
null.
update()
Model.update(filter, update, options, callback)
-
options- multi: по умолчанию
falseОбновить только первые данные;true, несколько документов, соответствующих условиям запроса, будут обновлены. - перезаписать: по умолчанию
false,Прямо сейчасupdateЕсли у параметра нет оператора или оператор не является оператором обновления, он будет добавлен по умолчанию$set; еслиtrue, то не добавляйте$set, который считается перезаписывающим исходный документ.
- multi: по умолчанию
updateMany()
Model.updateMany(filter, update, options, callback)
Обновите все документы, соответствующие критериям запроса, эквивалентныеModel.update(filter, update, { multi: true }, callback)
удалять
удалить общийfindOneAndDelete(),findByIdAndDelete(),deleteMany(),findByIdAndRemove()Ждать.
findOneAndDelete()
Model.findOneAndDelete(filter, options, callback)
-
filterзапрос иfind()Такой же -
options- sort: если условие запроса находит несколько документов, установите порядок сортировки, чтобы выбрать, какой документ удалить.
- select/projection: определяет возвращаемые поля.
- rawResult: если
true, возвращение изMongoDBродной результат.
-
callback- не встретились
filterданные, возвратnull. -
filterпустой или{}, удалите первые данные. - Удаление успешно возвращено
{}Сформировать исходные данные.
- не встретились
findByIdAndDelete()
Model.findByIdAndDelete(id, options, callback)
Model.findByIdAndDelete(id)эквивалентноModel.findOneAndDelete({ _id: id }).
-
callback- не встретились
idданные, возвратnull. -
idпустой илиundefined, вернутьnull. - Удаление успешно возвращено
{}необработанные данные в форме.
- не встретились
deleteMany()
Model.deleteMany(filter, options, callback)
-
filterудалить все совпаденияfilterусловная документация.
deleteOne()
Model.deleteOne(filter, options, callback)
-
filterудалить совпадениеfilterПервый документ условия.
findOneAndRemove()
Model.findOneAndRemove(filter, options, callback)
использование сfindOneAndDelete()Опять небольшая разницаfindOneAndRemove()вызовет родной MongoDBfindAndModify()команда вместоfindOneAndDelete()Заказ.
Рекомендуется использоватьfindOneAndDelete()метод.
findByIdAndRemove()
Model.findByIdAndRemove(id, options, callback)
Model.findByIdAndRemove(id)эквивалентноModel.findOneAndRemove({ _id: id }).
remove()
Model.remove(filter, options, callback)
Удалить все совпадения из набораfilterусловная документация. Чтобы удалить первый документ, соответствующий критериям, используйтеsingleпараметры установлены наtrue.
прочитай этоModels, и, наконец, давайте взглянем на более полезные в реальном боюPopulate
Совместная таблица (заполнить)
мангустаpopulate()Могу连表查询, то есть ссылаясь на его документы в другой коллекции.
Populate()можно заменить автоматическиdocumentуказанные поля в, заменить содержимое из другихcollectionполучено в.
refs
СоздайтеModelкогдаModelассоциативное хранилище для других коллекций_idнастройки поляrefопции.refварианты говорятMongooseВ использованииpopulate()что использовать при заливкеModel.
const mongoose = require("mongoose");
const { Schema, model } = mongoose;
const answerSchema = new Schema(
{
__v: { type: Number, select: false },
content: { type: String, required: true },
answerer: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
select: false
},
questionId: { type: String, required: true },
voteCount: { type: Number, required: true, default: 0 }
},
{ timestamps: true }
);
module.exports = model("Answer", answerSchema);
В приведенном выше примереAnswerмоделиanswererПоле устанавливается в массив ObjectIds. Опция ref говорит Mongoose использоватьUserмодель. Все хранится вanswererсередина_idдолжно бытьUserв моделиdocumentиз_id.
ObjectId,Number,Stringтак же какBufferможно использовать какrefsиспользовать. Но лучше использоватьObjectId.
Сохранить при создании документаrefsПоле аналогично сохранению обычного свойства, поместите_idПросто присвойте ему значение.
const Answer = require("../models/answers");
async create(ctx) {
ctx.verifyParams({
content: { type: "string", required: true }
});
const answerer = ctx.state.user._id;
const { questionId } = ctx.params;
const answer = await new Answer({
...ctx.request.body,
answerer,
questionId
}).save();
ctx.body = answer;
}
populate(path,select)
填充document
const Answer = require("../models/answers");
const answer = await Answer.findById(ctx.params.id)
.select(selectFields)
.populate("answerer");
заполненныйanswererПоле больше не является исходным_id, но указаноdocumentзаменять. этоdocumentдругимqueryвозвращается из базы данных.
返回字段选择
Если только нужно заполнитьdocumentчасть полей можно отдатьpopulate()Передайте второй параметр, форма параметра返回字段字符串,такой жеQuery.prototype.select().
const answer = await Answer.findById(ctx.params.id)
.select(selectFields)
.populate("answerer", "name -_id");
populate 多个字段
const populateStr =
fields &&
fields
.split(";")
.filter(f => f)
.map(f => {
if (f === "employments") {
return "employments.company employments.job";
}
if (f === "educations") {
return "educations.school educations.major";
}
return f;
})
.join(" ");
const user = await User.findById(ctx.params.id)
.select(selectFields)
.populate(populateStr);
наконец
Эта статья закончилась здесь, здесь в основном комбинация моих обычных проектов (https://github.com/Jack-cool/rest_node_api) дляmongooseКратко об использовании. Надеюсь, это поможет вам!
В то же время, вы можете обратить внимание на мой одноименный паблик [Front-end Forest], где я буду регулярно публиковать несколько актуальных статей, связанных с большим фронт-эндом, и практические итоги в ежедневном процессе разработки.