<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Códice | Entradas sobre «paginate»</title><description>Feed RSS de publicaciones etiquetadas con paginate</description><link>https://javguerra.github.io/</link><item><title>Usando populate con paginate y filtrando los resultados</title><link>https://javguerra.github.io/blog/populate-paginate-fitrado</link><guid isPermaLink="true">https://javguerra.github.io/blog/populate-paginate-fitrado</guid><description>Cómo relacionar colecciones cuando se usa mongoose-paginate-v2</description><pubDate>Sat, 29 Oct 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;https://javguerra.github.io/_astro/mongoose.yK9gFAu8_Z1xJtaI.webp&quot; alt=&quot;mongoose-paginate-v2&quot; style=&quot;max-width: 100%; height: auto;&quot; /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Etiquetas:&lt;/strong&gt; &lt;em&gt;#código&lt;/em&gt;, &lt;em&gt;#javascript&lt;/em&gt;, &lt;em&gt;#node.js&lt;/em&gt;, &lt;em&gt;#mongodb&lt;/em&gt;, &lt;em&gt;#mongoose&lt;/em&gt;, &lt;em&gt;#paginate&lt;/em&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Si bien mongodb tiene formas de obtener resultados paginados (limit, skip), el módulo mongoose-paginate-v2 de mongoose nos ahorra tiempo y código a la hora de preparar y usar los datos paginados obtenidos de las búsquedas en nuestras bases de datos, devolviendo información complementaria muy cómoda, pero ¿cómo podemos usar la paginación cuando tenemos relaciones entre colecciones? En esta entrada explicaré cómo paginar resultados agregados entre colecciones como si usásemos aggregate en mongodb o populate en mongoose, y además cómo filtrar búsquedas agregadas y paginadas con este módulo.&lt;/p&gt;
&lt;h1 id=&quot;el-ejemplo&quot;&gt;El ejemplo&lt;/h1&gt;
&lt;p&gt;Imaginemos que tenemos dos colecciones en una BBDD mongodb, una de &lt;code&gt;libros&lt;/code&gt; y otra de &lt;code&gt;autores&lt;/code&gt;, y un dato en cada documento de la colección libros llamado &lt;code&gt;autor&lt;/code&gt; que sirve para contener la información agregada del autor en la colección libros. En el &lt;em&gt;schema&lt;/em&gt;, el dato &lt;code&gt;autor&lt;/code&gt; podría tener esta forma:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    autor&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        ref&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: { &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: Schema.Types.ObjectId, &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;ref&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;Autor&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;        nombre&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;: String&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;La propiedad &lt;code&gt;ref&lt;/code&gt; es la que «tenderá el puente» entre ambas colecciones, y contendrá el &lt;code&gt;_id&lt;/code&gt; del documento a relacionar de la colección &lt;code&gt;autores&lt;/code&gt;. La propiedad &lt;code&gt;nombre&lt;/code&gt; contendrá, como se espera, el nombre del autor. Si bien este dato estará también en la colección &lt;code&gt;autores&lt;/code&gt;, y puede ser redundante cuando agregamos los resultados, el dato tiene su utilidad, pues nos permite realizar el filtrado de libros por autor incluso sin realizar la agregación.&lt;/p&gt;
&lt;p&gt;Una búsqueda haciendo uso de populate tendría esta forma:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Libro.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;find&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;( filtro ).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;populate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;( &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;autor.ref&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ).&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;exec&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;donde &lt;code&gt;filtro&lt;/code&gt; es un objeto que contendrá los criterios de búsqueda, y &lt;code&gt;autor.ref&lt;/code&gt; es la necesaria referencia para poder llevar a cabo la agregación de datos de la colección &lt;code&gt;autores&lt;/code&gt; en &lt;code&gt;libros&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Si queremos emplear el módulo &lt;code&gt;mongoose-paginate-v2&lt;/code&gt; para paginar los resultados de la búsqueda, esta quedaría de la siguiente forma:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Libro.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paginate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(filtro, { page, limit });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;donde &lt;code&gt;page&lt;/code&gt; indica la página de resultados a obtener y &lt;code&gt;limit&lt;/code&gt; el número de resultados por página.&lt;/p&gt;
&lt;p&gt;Pero sólo nos devolverá los datos de la colección &lt;code&gt;autores&lt;/code&gt;, sin agregar los datos de la colección &lt;code&gt;libros&lt;/code&gt;. ¿Cómo se haría esto?&lt;/p&gt;
&lt;h1 id=&quot;agregando-y-paginando&quot;&gt;Agregando y paginando&lt;/h1&gt;
&lt;p&gt;Hemos visto que paginate acepta dos parámetros, los criterios de búsqueda (filtro) y las opciones (page, limit). Otra opción que podemos añadir a paginate es &lt;code&gt;populate&lt;/code&gt;. Para hacer una búsqueda agregada como la del ejemplo, usaríamos:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Libro.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paginate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(filtro, { page, limit, populate: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;autor.ref&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;de esta forma podemos obtener un resultado con la información de ambas colecciones.&lt;/p&gt;
&lt;p&gt;La opción populate permite también otras opciones. Imaginemos que en la agregación queremos obviar el dato &lt;code&gt;nombre&lt;/code&gt; de la colección &lt;code&gt;autores&lt;/code&gt; que ya tenemos en la colección &lt;code&gt;libros&lt;/code&gt;. Podemos pasarle a &lt;code&gt;populate&lt;/code&gt; un objeto de la siguiente forma:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Libro.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paginate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(filtro, { page, limit, populate: {path: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;autor.ref&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, select: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;-nombre&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos; })&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;donde &lt;code&gt;select: &apos;-nombre&apos;&lt;/code&gt;, que va con un signo menos (-) delante, indica que ese dato no será requerido. Véase también que, para incluir la referencia a la colección, dentro del objeto se usa &lt;code&gt;path: &apos;autor.ref&apos;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Puedes obtener más información sobre las &lt;a href=&quot;https://mongoosejs.com/docs/api.html#query_Query-populate&quot;&gt;opciones de populate&lt;/a&gt; en el manual on-line.&lt;/p&gt;
&lt;h1 id=&quot;filtrando&quot;&gt;Filtrando&lt;/h1&gt;
&lt;p&gt;Decía más arriba que nos puede interesar hacer un filtrado en la búsqueda sobre nuestra base de datos por el nombre del autor, que es un dato dentro de otro dato, pero antes recordaré cómo buscar por uno o varios datos de la colección.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; filtro&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (titulo) filtro.titulo &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { $regex: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`.*${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;titulo&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}.*`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (precio) filtro.precio &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { $lte: precio };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Este código creará un objeto &lt;code&gt;filtro&lt;/code&gt; que permitirá que busquemos en la colección &lt;code&gt;libros&lt;/code&gt; por título y precio, ya que, si estos datos de búsqueda existen, con &lt;code&gt;filtro.titulo&lt;/code&gt; y &lt;code&gt;filtro.precio&lt;/code&gt; añadimos ambas propiedades al objeto filtro que usaremos en la búsqueda de la forma en que hemos visto en todos los ejemplos anteriores. (Nota: entiéndase que podríamos tener libros con el mismo título y distinto precio según la editorial o la colección editorial).&lt;/p&gt;
&lt;p&gt;Con &lt;code&gt;{ $regex: `.*${titulo}.*/` }&lt;/code&gt; buscamos por la expresión regular dada, en cambio con &lt;code&gt;$lte: precio&lt;/code&gt; buscamos por un valor igual o menor al proporcionado. Ver más información sobre &lt;a href=&quot;https://www.mongodb.com/docs/manual/reference/operator/&quot;&gt;operadores de búsqueda en mongodb&lt;/a&gt; en el manual on-line.&lt;/p&gt;
&lt;p&gt;Esto permitirá que:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;Libro.&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;paginate&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(filtro, { page, limit, populate: {path: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;autor.ref&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;, select: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos;-nombre&apos;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&apos; })&lt;/span&gt;&lt;span style=&quot;color:#FDAEB7;font-style:italic&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;devuelva aquellos documentos de la colección &lt;code&gt;libros&lt;/code&gt; que tengan coincidencias con el &lt;code&gt;filtro&lt;/code&gt; indicado, es decir, que contengan en el título el texto &lt;code&gt;titulo&lt;/code&gt; indicado y cuyo precio sea igual o menor al &lt;code&gt;precio&lt;/code&gt; indicado.&lt;/p&gt;
&lt;h2 id=&quot;consulta-sobre-datos-anidados&quot;&gt;Consulta sobre datos anidados&lt;/h2&gt;
&lt;p&gt;Teniendo claro lo anterior, acceder al dato &lt;code&gt;nombre&lt;/code&gt; dentro de &lt;code&gt;autor&lt;/code&gt; no es complicado, pero para referenciar el dato tendremos que usar lo siguiente:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;javascript&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; filtro&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (nombre) filtro[&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;autor.nombre&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { $regex: &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;`.*${&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;nombre&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;}.*`&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; };&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Uso aquí los corchetes &lt;code&gt;[]&lt;/code&gt; porque para poder usar el filtro en mongodb debo pasarle la propiedad al objeto filtro de esta forma: &lt;code&gt;{ &quot;autor.nombre&quot; : { $regex: `.*${nombre}.*` } }&lt;/code&gt; como se indica en la sección &lt;a href=&quot;https://www.mongodb.com/docs/manual/tutorial/query-embedded-documents/&quot;&gt;consulta sobre documentos incrustados/anidados&lt;/a&gt; del manual online.&lt;/p&gt;
&lt;p&gt;Este filtro devolverá aquellos documentos de la colección &lt;code&gt;libros&lt;/code&gt; que, dentro del dato &lt;code&gt;autor&lt;/code&gt;, contengan el nombre dado dentro del dato anidado &lt;code&gt;nombre&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id=&quot;enlaces&quot;&gt;Enlaces&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/mongoose-paginate-v2&quot;&gt;mongoose-paginate-v2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mongoosejs.com/docs/api.html#query_Query-populate&quot;&gt;Opciones de populate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/reference/operator/&quot;&gt;Operadores de búsqueda en mongodb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.mongodb.com/docs/manual/tutorial/query-embedded-documents/&quot;&gt;Consulta sobre documentos incrustados/anidados&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><enclosure url="https://javguerra.github.io/_astro/mongoose.yK9gFAu8_Z1xJtaI.webp"/><category>código</category><category>javascript</category><category>node.js</category><category>mongodb</category><category>mongoose</category><category>paginate</category><author>JavGuerra</author></item></channel></rss>