Execpopulate mongoose что это
Execpopulate mongoose что это
Populate
Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). We may populate a single document, multiple documents, a plain object, multiple plain objects, or all objects returned from a query. Let’s look at some examples.
So far we’ve created two Models. Our Person model has its stories field set to an array of ObjectId s. The ref option is what tells Mongoose which model to use during population, in our case the Story model. All _id s we store here must be document _id s from the Story model.
Saving refs
Saving refs to other documents works the same way you normally save properties, just assign the _id value:
Population
Arrays of refs work the same way. Just call the populate method on the query and an array of documents will be returned in place of the original _id s.
Setting Populated Fields
You can manually populate a property by setting it to a document. The document must be an instance of the model your ref property refers to.
Checking Whether a Field is Populated
You can call the populated() function to check whether a field is populated. If populated() returns a truthy value, you can assume the field is populated.
A common reason for checking whether a path is populated is getting the author id. However, for your convenience, Mongoose adds a _id getter to ObjectId instances so you can use story.author._id regardless of whether author is populated.
What If There’s No Foreign Document?
Field Selection
What if we only want a few specific fields returned for the populated documents? This can be accomplished by passing the usual field name syntax as the second argument to the populate method:
Populating Multiple Paths
What if we wanted to populate multiple paths at the same time?
If you call populate() multiple times with the same path, only the last one will take effect.
Query conditions and other options
What if we wanted to populate our fans array based on their age and select just their names?
If you want to filter stories by their author’s name, you should use denormalization.
limit vs. perDocumentLimit
Populate does support a limit option, however, it currently does not limit on a per-document basis for backwards compatibility. For example, suppose you have 2 stories:
If you were to populate() using the limit option, you would find that the 2nd story has 0 fans:
Refs to children
There are two perspectives here. First, you may want the author to know which stories are theirs. Usually, your schema should resolve one-to-many relationships by having a parent pointer in the ‘many’ side. But, if you have a good reason to want an array of child pointers, you can push() documents onto the array as shown below.
This allows us to perform a find and populate combo:
It is debatable that we really want two sets of pointers as they may get out of sync. Instead we could skip populating and directly find() the stories we are interested in.
The documents returned from query population become fully functional, remove able, save able documents unless the lean option is specified. Do not confuse them with sub docs. Take caution when calling its remove method because you’ll be removing it from the database, not just the array.
Populating an existing document
If you have an existing mongoose document and want to populate some of its paths, you can use the Document#populate() method.
The Document#populate() method does not support chaining. You need to call populate() multiple times, or with an array of paths, to populate multiple paths
Populating multiple existing documents
If we have one or many mongoose documents or even plain objects (like mapReduce output), we may populate them using the Model.populate() method. This is what Document#populate() and Query#populate() use to populate documents.
Populating across multiple levels
Say you have a user schema which keeps track of the user’s friends.
Populate lets you get a list of a user’s friends, but what if you also wanted a user’s friends of friends? Specify the populate option to tell mongoose to populate the friends array of all the user’s friends:
Cross Database Populate
Let’s say you have a schema representing events, and a schema representing conversations. Each event has a corresponding conversation thread.
This is known as a «cross-database populate,» because it enables you to populate across MongoDB databases and even across MongoDB instances.
Dynamic References via `refPath`
Mongoose can also populate from multiple collections based on the value of a property in the document. Let’s say you’re building a schema for storing comments. A user may comment on either a blog post or a product.
Defining separate blogPost and product properties works for this simple example. But, if you decide to allow users to also comment on articles or other comments, you’ll need to add more properties to your schema. You’ll also need an extra populate() call for every property, unless you use mongoose-autopopulate. Using refPath means you only need 2 schema paths and one populate() call regardless of how many models your commentSchema can point to.
Populate Virtuals
Unfortunately, these two schemas, as written, don’t support populating an author’s list of blog posts. That’s where virtual populate comes in. Virtual populate means calling populate() on a virtual property that has a ref option as shown below.
You can then populate() the author’s posts as shown below.
If you’re using populate projections, make sure foreignField is included in the projection.
Populate Virtuals: The Count Option
Populate virtuals also support counting the number of documents with matching foreignField as opposed to the documents themselves. Set the count option on your virtual:
Populating Maps
Maps are a type that represents an object with arbitrary string keys. For example, in the below schema, members is a map from strings to ObjectIds.
You can populate() every book’s author by populating books.$*.author :
Populate in Middleware
You can populate in either pre or post hooks. If you want to always populate a certain field, check out the mongoose-autopopulate plugin.
Next Up
Mongoose populate after save
This is where I am pulling my hair
EDIT: latest mongoose fixed this issue and added populate functionality, see the new accepted answer.
13 Answers 13
You should be able to use the Model’s populate function to do this: http://mongoosejs.com/docs/api.html#model_Model.populate In the save handler for book, instead of:
you’d do something like:
Probably too late an answer to help you, but I was stuck on this recently, and it might be useful for others.
In case that anyone is still looking for this.
Mongoose 3.6 has introduced a lot of cool features to populate:
But this way you would still query for the user again.
A little trick to accomplish it without extra queries would be:
The solution which returns a promise (no callbacks):
Use Document#populate
Possible Implementation
Read about document population here.
Just to elaborate and give another example, as it helped me out. This might help those who want to to retrieve partially populated objects after save. The method is slightly different as well. Spent more than an hour or two looking for the correct way to do it.
I thought I’d add to this to clarify things for complete noobs like myself.
What’s massively confusing if you’re not careful is that there are three very different populate methods. They are methods of different objects (Model vs. Document), take different inputs and give different outputs (Document vs. Promise).
Here they are for those that are baffled:
Document.prototype.populate()
This one works on documents and returns a document. In the original example, it would look like this:
Because it works on documents and returns a document, you can chain them together like so:
But don’t be silly, like me, and try to do this:
Remember: Document.prototype.populate() returns a document, so this is nonsense. If you want a promise, you need.
Document.prototype.execPopulate()
This one works on documents BUT it returns a promise that resolves to the document. In other words, you can use it like this:
That’s better. Finally, there’s.
Model.populate()
This one works on models and returns a promise. It’s therefore used a bit differently:
NoSQL привнес гибкость в табличный мир баз данных. В частности, MongoDB стал отличным вариантом для хранения неструктурированных документов JSON. Данные начинаются как JSON в пользовательском интерфейсе и претерпевают очень мало преобразований для сохранения, поэтому мы получаем преимущества от повышения производительности и сокращения времени обработки.
Но NoSQL не означает полного отсутствия структуры. Нам все еще нужно проверить и преобразовать наши данные перед их сохранением, и нам все еще может потребоваться применить к ним некоторую бизнес-логику. Это место, которое заполняет Mongoose.
В этой статье мы узнаем на примере приложения, как мы можем использовать Mongoose для моделирования наших данных и проверки их перед сохранением в MongoDB.
Что такое Mongoose?
Как работает MongoDB
Связанные документы могут храниться в коллекциях, подобных таблицам в реляционных базах данных. На этом аналогия заканчивается, поскольку мы определяем, что считать «связанными документами».
MongoDB не навязывает структуру документов. Например, мы можем сохранить этот документ в коллекцию Person :
А затем в той же коллекции мы могли бы сохранить, казалось бы, несвязанный документ без общих свойств или структуры:
В этом заключается новизна баз данных NoSQL. Мы придаем смысл нашим данным и храним их так, как нам кажется лучше. База данных не налагает никаких ограничений.
Цель Mongoose
Хотя MongoDB не навязывает структуру, приложения обычно управляют данными с ее помощью. Мы получаем данные, и нам необходимо их проверить, чтобы убедиться, что мы получили именно то, что нам нужно. Нам также может потребоваться обработать данные каким-либо образом перед их сохранением. Здесь и вступает в игру Mongoose.
Давайте теперь посмотрим, как определить схему.
Установка Mongoose и создание схемы Person
Давайте запустим проект Node со свойствами по умолчанию и схемой Person:
Чтобы работать с Mongoose, нам нужно импортировать его в наши скрипты:
А затем подключитесь к базе данных с помощью:
Созданного контейнера нам будет достаточно, чтобы попробовать Mongoose, хотя данные, сохраненные в MongoDB, не будут постоянными.
Схема и модель Person
После предыдущих необходимых объяснений мы можем сосредоточиться на написании нашей схемы человека и компиляции из нее модели.
Или еще проще, вот так:
Ссылка на другие схемы
Мы можем ожидать, что все приложения среднего размера будут иметь более одной схемы, и, возможно, эти схемы будут каким-то образом связаны.
В нашем примере, чтобы представить генеалогическое древо, нам нужно добавить в нашу схему два атрибута:
Наш случай немного особенный, потому что оба mother и father также будут содержать людей, но способ определения этих отношений одинаков во всех случаях.
Встроенная проверка
Пользовательская проверка
Встроенные SchemaType позволяют настраивать собственные проверки. Это особенно полезно, когда у нас есть свойство, которое может содержать только определенные значения. Добавим свойство photosURLs в наш массив URL-адресов их фотографий Person :
Например, пакет mongoose-type-url, который мы могли бы использовать вместо нашей валидации.
Виртуальные свойства
Посмотрим, как этого добиться после определения нашей первоначальной схемы:
Приведенное выше виртуальное свойство fullName делает некоторые предположения для простоты: у каждого человека есть как минимум имя и фамилия. Мы столкнемся с проблемами, если у человека есть отчество, составное имя или фамилия. Все эти ограничения могут быть закреплены внутри get() и set() функции, определенные выше.
ПО промежуточного слоя
Создайте модель для схемы
Метод model() делает копию всего что мы определили в схеме. Он также содержит все методы Mongoose, которые мы будем использовать для взаимодействия с базой данных.
Мы можем импортировать модуль таким образом:
Как использовать модель
Модель, которую мы скомпилировали в последнем разделе, содержит все, что нам нужно для взаимодействия с коллекцией в базе данных.
Давайте теперь посмотрим, как мы будем использовать нашу модель для всех операций CRUD.
Создание Person
Мы можем создать Person, просто выполнив:
name это единственное обязательное свойство. Давайте создадим другого человека, но на этот раз с использованием виртуального свойства:
Теперь, когда у нас есть первые два человека, мы можем создать нового со всеми заполненными свойствами, включая родителей:
Все значения для этого последнего человека установлены на допустимые, так как проверка выдаст ошибку, как только эта строка будет выполнена. Например, если бы мы установили URL-адрес первой фотографии не на ссылку, мы бы получили ошибку:
Как объяснялось ранее, родители были заполнены идентификаторами первых двух человек, а не объектами.
Мы создали трех человек, но они еще не сохранены в базе данных. Сделаем это дальше:
Операции с базой данных асинхронны. Если мы хотим дождаться завершения, мы можем использовать async / await:
Получить одно или несколько Person
Все методы поиска в Mongoose требуют аргумента для фильтрации поиска. Вернемся к последнему созданному нами человеку:
Поскольку мы прикрепили к методу findOne() ловушку для заполнения родителей человека, теперь мы можем обращаться к ним напрямую:
В нашем случае мы знаем, что запрос вернет только один результат, но даже если более одного человека соответствует фильтру, будет возвращен только первый результат.
Мы можем получить более одного результата, если воспользуемся методом find() :
Мы вернем массив, который сможем перебрать.
Обновление Person
Если у нас уже есть Person, так как мы только что его создали или извлекли, мы можем обновить и сохранить изменения, выполнив следующие действия:
Поскольку оба человека уже существуют в базе данных, Mongoose отправит команду обновления только с измененными полями, а не со всем документом.
Удалить Person
Как и поиск, удаление может быть выполнено для одного или нескольких Person:
После выполнения этих двух команд коллекция будет пустой.
Вывод
В этой статье мы увидели, как Mongoose может быть очень полезен в наших проектах NodeJS и MongoDB.
В большинстве проектов с MongoDB нам необходимо хранить данные в определенном формате. Приятно знать, что Mongoose предоставляет простой способ моделирования и проверки этих данных.
Execpopulate mongoose что это
Population is the process of automatically replacing the specified paths in the document with document(s) from other collection(s). We may populate a single document, multiple documents, plain object, multiple plain objects, or all objects returned from a query. Let’s look at some examples.
So far we’ve created two Models. Our Person model has its stories field set to an array of ObjectId s. The ref option is what tells Mongoose which model to use during population, in our case the Story model. All _id s we store here must be document _id s from the Story model.
Saving refs
Saving refs to other documents works the same way you normally save properties, just assign the _id value:
Population
Arrays of refs work the same way. Just call the populate method on the query and an array of documents will be returned in place of the original _id s.
Note: mongoose >= 3.6 exposes the original _ids used during population through the document#populated() method.
Setting Populated Fields
In Mongoose >= 4.0, you can manually populate a field as well.
Note that this only works for single refs. You currently can’t manually populate an array of refs.
Field selection
What if we only want a few specific fields returned for the populated documents? This can be accomplished by passing the usual field name syntax as the second argument to the populate method:
Populating multiple paths
What if we wanted to populate multiple paths at the same time?
If you call populate() multiple times with the same path, only the last one will take effect.
Query conditions and other options
What if we wanted to populate our fans array based on their age, select just their names, and return at most, any 5 of them?
Refs to children
There are two perspectives here. First, you may want the author know which stories are theirs. Usually, your schema should resolve one-to-many relationships by having a parent pointer in the ‘many’ side. But, if you have a good reason to want an array of child pointers, you can push() documents onto the array as shown below.
This allows us to perform a find and populate combo:
It is debatable that we really want two sets of pointers as they may get out of sync. Instead we could skip populating and directly find() the stories we are interested in.
The documents returned from query population become fully functional, remove able, save able documents unless the lean option is specified. Do not confuse them with sub docs. Take caution when calling its remove method because you’ll be removing it from the database, not just the array.
Populating an existing document
If we have an existing mongoose document and want to populate some of its paths, mongoose >= 3.6 supports the document#populate() method.
Populating multiple existing documents
If we have one or many mongoose documents or even plain objects (like mapReduce output), we may populate them using the Model.populate() method available in mongoose >= 3.6. This is what document#populate() and query#populate() use to populate documents.
Populating across multiple levels
Say you have a user schema which keeps track of the user’s friends.
Populate lets you get a list of a user’s friends, but what if you also wanted a user’s friends of friends? Specify the populate option to tell mongoose to populate the friends array of all the user’s friends:
Populating across Databases
Let’s say you have a schema representing events, and a schema representing conversations. Each event has a corresponding conversation thread.
Also, suppose that events and conversations are stored in separate MongoDB instances.
In this situation, you will not be able to populate() normally. The conversation field will always be null, because populate() doesn’t know which model to use. However, you can specify the model explicitly.
This is known as a «cross-database populate,» because it enables you to populate across MongoDB databases and even across MongoDB instances.
Dynamic References
Populate Virtuals
So far you’ve only populated based on the _id field. However, that’s sometimes not the right choice. In particular, arrays that grow without bound are a MongoDB anti-pattern. Using mongoose virtuals, you can define more sophisticated relationships between documents.
If you’re using populate projections, make sure foreignField is included in the projection.
Next Up
Now that we’ve covered query population, let’s take a look at connections.
Mongoose населяют после сохранения
Вот где я тяну свои волосы
EDIT: последний mongoose исправил эту проблему и добавил функцию заполнения, см. новый принятый ответ.
ОТВЕТЫ
Ответ 1
Вы можете использовать функцию заполнения модели для этого: http://mongoosejs.com/docs/api.html#model_Model.populate В обработчике сохранения для книги вместо
вы бы сделали что-то вроде:
Возможно, слишком поздно ответить, чтобы помочь вам, но я недавно застрял в этом, и это может быть полезно для других.
Ответ 2
Если кто-то все еще ищет это.
Mongoose 3.6 представила множество интересных функций для заполнения:
Но таким образом вы все равно будете запрашивать пользователя снова.
Небольшой трюк для выполнения этого без дополнительных запросов будет:
Ответ 3
Просто чтобы уточнить и привести еще один пример, поскольку он помог мне. Это может помочь тем, кто хочет получить частично заполненные объекты после сохранения. Метод также немного отличается. Прошло более часа или двух, ища правильный способ сделать это.
Ответ 4
Решение, которое возвращает обещание (без обратных вызовов):
Использовать документ # populate
Возможная реализация
Читайте о документе населения здесь.
Ответ 5
Ответ 6
Я думал, что добавлю к этому, чтобы прояснить ситуацию для полных нубов, подобных мне.
Что массово запутывает, если вы не осторожны, так это три разных метода заполнения. Это методы разных объектов (Model vs. Document), используют разные входы и дают разные результаты (Document vs. Promise).
Здесь они предназначены для тех, кто озадачен:
Document.prototype.populate()
Этот документ работает с документами и возвращает документ. В исходном примере это будет выглядеть так:
Поскольку он работает с документами и возвращает документ, вы можете связать их следующим образом:
Но не будьте глупыми, как я, и постарайтесь сделать это:
Помните: Document.prototype.populate() возвращает документ, так что это вздор. Если вам нужно обещание, вам нужно.
Document.prototype.execPopulate()
Это работает над документами, но возвращает обещание, которое разрешает документ. Другими словами, вы можете использовать его следующим образом:
Это лучше. Наконец, есть.
Model.populate()
Это работает на моделях и возвращает обещание. Поэтому он использовался несколько иначе:
Надеюсь, что это помогло другим новичкам.
Ответ 7
К сожалению, это давняя проблема с мангустом, который, я считаю, еще не решен:
Что вы можете сделать, так это написать собственный пользовательский getter/setter (и установить real _customer в отдельном свойстве). Например:
Ответ 8
Был бы самый приятный и наименее проблематичный способ сделать эту работу (с помощью Bluebird promises).
Ответ 9
Это работает для меня (просто много головной боли!)
Ответ 10
закончил тем, что написал некоторые функции Promise, способные выполнять карри, где вы объявляете свои функции schema, query_adapter, data_adapter и заранее заполняете строку. Для более короткой/более простой реализации.
Это, вероятно, не суперэффективно, но я думал, что бит исполнения был довольно изящным.
