Вы действительно понимаете мангуста?

внешний интерфейс Mongoose
Вы действительно понимаете мангуста?

введение

Вслед за предыдущей статьей»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);

Доступные Варианты:

  • autoIndex
  • bufferCommands
  • capped
  • collection
  • id
  • _id
  • minimize
  • read
  • shardKey
  • strict
  • toJSON
  • toObject
  • typeKey
  • validateBeforeSave
  • versionKey
  • skipVersioning
  • timestamps

Здесь я просто перечисляю часто используемые элементы конфигурации, полные элементы конфигурации можно посмотреть в официальной документацииhttps://mongoosejs.com/docs/guide.html#options.

Здесь я в основном говорю оversionKeyа такжеtimestamps:

  • versionKey(упомянутый выше) автоматически устанавливается Mongoose при создании файла. Это значение содержит внутренний номер версии файла. versionKey — это строка, представляющая имя свойства номера версии, значение по умолчанию —__v
  • если установленоtimestampsвариант, мангуст автоматически добавит его в вашу схемуcreatedAtа такжеupdatedAtполе, тип которогоDate.

На данный момент основное введение завершеноSchema, смотри дальшеSchemaTypes

Типы схем

SchemaTypesВыберите значения по умолчанию для запросов и других значений пути обработки по умолчанию, проверок, геттеров, сеттеров, полей и специальных символов для строк и чисел. Допустимые типы схемы в мангусте:

  • String
  • Number
  • Date
  • Buffer
  • Boolean
  • Mixed
  • ObjectId
  • Array
  • Decimal128
  • Map

См. простой пример:

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

    Все входящие в Mongoosecallbackзапрос, формат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.
  • 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, который считается перезаписывающим исходный документ.

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], где я буду регулярно публиковать несколько актуальных статей, связанных с большим фронт-эндом, и практические итоги в ежедневном процессе разработки.