Spec-Zone.ru › Mongoose

Запросы

Мongoose модели предоставляют несколько статических вспомогательных функций для операций CRUD. Каждая из этих функций возвращает объект mongoose Query.

  • Model.deleteMany()
  • Model.deleteOne()
  • Model.find()
  • Model.findById()
  • Model.findByIdAndDelete()
  • Model.findByIdAndRemove()
  • Model.findByIdAndUpdate()
  • Model.findOne()
  • Model.findOneAndDelete()
  • Model.findOneAndRemove()
  • Model.findOneAndReplace()
  • Model.findOneAndUpdate()
  • Model.replaceOne()
  • Model.updateMany()
  • Model.updateOne()

Запрос mongoose может быть выполнен двумя способами. Во-первых, если вы передаете callback функцию, Mongoose выполнит запрос асинхронно и передаст результаты в callback.

Запрос также имеет .then() функцию и, следовательно, может использоваться как обещание.

Выполнение

При выполнении запроса вы указываете запрос в виде JSON-документа. Синтаксис JSON-документа такой же, как в консоли MongoDB.

const Person = mongoose.model('Person', yourSchema);

// find each person with a last name matching 'Ghost', selecting the `name` and `occupation` fields
const person = await Person.findOne({ 'name.last': 'Ghost' }, 'name occupation');
// Prints "Space Ghost is a talk show host".
console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation);

Что person зависит от операции: для findOne() это потенциально-нулевой единственный документ, find() список документов , count() число документов , update() число затронутых документов , и т. д. Более подробную информацию можно найти в документации API для моделей.

Теперь давайте посмотрим, что происходит, когда await не используется:

// find each person with a last name matching 'Ghost'
const query = Person.findOne({ 'name.last': 'Ghost' });

// selecting the `name` and `occupation` fields
query.select('name occupation');

// execute the query at a later time
const person = await query.exec();
// Prints "Space Ghost is a talk show host."
console.log('%s %s is a %s.', person.name.first, person.name.last, person.occupation);

В приведенном выше коде переменная query имеет тип Query. Query позволяет создавать запрос с использованием синтаксиса цепочки, а не указания JSON-объекта. Ниже приведены два эквивалентных примера.

// With a JSON doc
await Person.
  find({
    occupation: /host/,
    'name.last': 'Ghost',
    age: { $gt: 17, $lt: 66 },
    likes: { $in: ['vaporizing', 'talking'] }
  }).
  limit(10).
  sort({ occupation: -1 }).
  select({ name: 1, occupation: 1 }).
  exec();

// Using query builder
await Person.
  find({ occupation: /host/ }).
  where('name.last').equals('Ghost').
  where('age').gt(17).lt(66).
  where('likes').in(['vaporizing', 'talking']).
  limit(10).
  sort('-occupation').
  select('name occupation').
  exec();

Полный список вспомогательных функций запросов можно найти в документации API.

Запросы не являются обещаниями

Запросы Mongoose не являются обещаниями. Запросы являются thenable, что означает, что у них есть .then() метод для async/await для удобства. Однако, в отличие от обещаний, вызов .then() запроса выполняет запрос, поэтому вызов then() несколько раз приведет к ошибке.

const q = MyModel.updateMany({}, { isDeleted: true });

await q.then(() => console.log('Update 2'));
// Throws "Query was already executed: Test.updateMany({}, { isDeleted: true })"
await q.then(() => console.log('Update 3'));

Ссылки на другие документы

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

Потоковая обработка

Вы можете обрабатывать результаты запроса из MongoDB. Для этого необходимо вызвать функцию Query#cursor(), которая вернет экземпляр QueryCursor.

const cursor = Person.find({ occupation: /host/ }).cursor();

for (let doc = await cursor.next(); doc != null; doc = await cursor.next()) {
  console.log(doc); // Prints documents one at a time
}

Итерация по результатам запроса Mongoose с помощью асинхронных итераторов также создает курсор.

for await (const doc of Person.find()) {
  console.log(doc); // Prints documents one at a time
}

Курсоры могут быть подвержены таймаутам курсора. По умолчанию MongoDB закроет курсор через 10 минут, и последующие next() вызовы приведут к ошибке MongoServerError: cursor id 123 not found. Для отмены этого установите опцию noCursorTimeout в вашем курсоре.

// MongoDB won't automatically close this cursor after 10 minutes.
const cursor = Person.find().cursor().addCursorFlag('noCursorTimeout', true);

Однако, курсоры все еще могут истечь из-за таймаутов бездействия сессии. Таким образом, даже курсор с установленной опцией noCursorTimeout все равно истечет через 30 минут бездействия. Более подробную информацию о работе с таймаутами бездействия сессии можно найти в документации MongoDB.

Сравнение с агрегацией

Агрегация может выполнять многие те же действия, что и запросы. Например, ниже показано, как вы можете использовать aggregate() для поиска документов, где name.last = 'Ghost':

const docs = await Person.aggregate([{ $match: { 'name.last': 'Ghost' } }]);

Однако, только потому, что вы можете использовать aggregate(), не значит, что нужно. В целом, следует использовать запросы, когда это возможно, и использовать aggregate() только в крайних случаях.

В отличие от результатов запросов, Mongoose не hydrate() результаты агрегации. Результаты агрегации всегда являются POJO, а не документами Mongoose.

const docs = await Person.aggregate([{ $match: { 'name.last': 'Ghost' } }]);

docs[0] instanceof mongoose.Document; // false

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

const doc = await Person.findOne();

const idString = doc._id.toString();

// Finds the `Person`, because Mongoose casts `idString` to an ObjectId
const queryRes = await Person.findOne({ _id: idString });

// Does **not** find the `Person`, because Mongoose doesn't cast aggregation
// pipelines.
const aggRes = await Person.aggregate([{ $match: { _id: idString } }]);

Сортировка

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

const personSchema = new mongoose.Schema({
  age: Number
});

const Person = mongoose.model('Person', personSchema);
for (let i = 0; i < 10; i++) {
  await Person.create({ age: i });
}

await Person.find().sort({ age: -1 }); // returns age starting from 10 as the first entry
await Person.find().sort({ age: 1 }); // returns age starting from 0 as the first entry

При сортировке по нескольким полям порядок ключей сортировки определяет, по какому ключу MongoDB-сервер будет сортировать в первую очередь.

const personSchema = new mongoose.Schema({
  age: Number,
  name: String,
  weight: Number
});

const Person = mongoose.model('Person', personSchema);
const iterations = 5;
for (let i = 0; i < iterations; i++) {
  await Person.create({
    age: Math.abs(2 - i),
    name: 'Test' + i,
    weight: Math.floor(Math.random() * 100) + 1
  });
}

await Person.find().sort({ age: 1, weight: -1 }); // returns age starting from 0, but while keeping that order will then sort by weight.

Вы можете посмотреть результат одного выполнения этого блока ниже. Как видите, возраст сортируется от 0 до 2, но когда возраст одинаковый, сортируется по весу.

[
  {
    _id: new ObjectId('63a335a6b9b6a7bfc186cb37'),
    age: 0,
    name: 'Test2',
    weight: 67,
    __v: 0
  },
  {
    _id: new ObjectId('63a335a6b9b6a7bfc186cb35'),
    age: 1,
    name: 'Test1',
    weight: 99,
    __v: 0
  },
  {
    _id: new ObjectId('63a335a6b9b6a7bfc186cb39'),
    age: 1,
    name: 'Test3',
    weight: 73,
    __v: 0
  },
  {
    _id: new ObjectId('63a335a6b9b6a7bfc186cb33'),
    age: 2,
    name: 'Test0',
    weight: 65,
    __v: 0
  },
  {
    _id: new ObjectId('63a335a6b9b6a7bfc186cb3b'),
    age: 2,
    name: 'Test4',
    weight: 62,
    __v: 0
  }
];

Далее

Теперь, когда мы рассмотрели Queries, давайте посмотрим на валидацию.

© 2010 LearnBoost
Licensed under the MIT License.
https://mongoosejs.com/docs/queries.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API