UNPKG

@teamnet/ic-orm

Version:

Database Management System for Total.js v4 and standalone

829 lines (643 loc) 16.9 kB
# 🔍 Query Builder Avanzado - MongoDB con icorm Guía completa del Query Builder para construir consultas complejas de forma fluida y encadenable. ## 📋 Tabla de Contenidos - [WHERE - Condiciones](#where---condiciones) - [IN/NOTIN - Arrays de Valores](#innotin---arrays-de-valores) - [BETWEEN - Rangos](#between---rangos) - [SEARCH - Búsqueda de Texto](#search---búsqueda-de-texto) - [SORT - Ordenamiento](#sort---ordenamiento) - [FIELDS - Proyección de Campos](#fields---proyección-de-campos) - [TAKE/SKIP - Paginación](#takeskip---paginación) - [OR - Condiciones OR](#or---condiciones-or) - [Métodos de Encadenamiento](#métodos-de-encadenamiento) - [Ejemplos Complejos](#ejemplos-complejos) --- ## 🎯 WHERE - Condiciones Filtra documentos por condiciones específicas. ### Sintaxis ```javascript .where(field, value) .where(field, operator, value) ``` ### Operadores Soportados | Operador | MongoDB | Descripción | |----------|---------|-------------| | `=` o `==` | `$eq` | Igual a | | `!=` o `<>` | `$ne` | Diferente de | | `>` | `$gt` | Mayor que | | `>=` | `$gte` | Mayor o igual que | | `<` | `$lt` | Menor que | | `<=` | `$lte` | Menor o igual que | ### Ejemplos #### Igualdad Simple ```javascript // WHERE active = true var users = await DBMS() .find('users') .where('active', true) .promise(); // WHERE email = 'john@example.com' var user = await DBMS() .one('users') .where('email', 'john@example.com') .promise(); ``` #### Comparaciones Numéricas ```javascript // WHERE age > 18 var adults = await DBMS() .find('users') .where('age', '>', 18) .promise(); // WHERE age >= 18 AND age <= 65 var workingAge = await DBMS() .find('users') .where('age', '>=', 18) .where('age', '<=', 65) .promise(); // WHERE price < 100 var cheap = await DBMS() .find('products') .where('price', '<', 100) .promise(); ``` #### Búsqueda por _id ```javascript // WHERE _id = ObjectId('...') var user = await DBMS() .one('users') .where('_id', '507f1f77bcf86cd799439011') .promise(); // icorm convierte automáticamente el string a ObjectId ``` #### Múltiples Condiciones (AND) ```javascript // WHERE active = true AND age >= 18 AND verified = true var users = await DBMS() .find('users') .where('active', true) .where('age', '>=', 18) .where('verified', true) .promise(); // Todas las condiciones se unen con AND automáticamente ``` #### Condiciones con null/undefined ```javascript // Buscar documentos donde email es null var noEmail = await DBMS() .find('users') .where('email', null) .promise(); // Buscar documentos donde deletedAt NO es null var deleted = await DBMS() .find('users') .where('deletedAt', '!=', null) .promise(); ``` --- ## 📋 IN/NOTIN - Arrays de Valores Filtra por múltiples valores posibles. ### Sintaxis ```javascript .in(field, arrayOfValues) .notin(field, arrayOfValues) ``` ### Ejemplos #### IN Básico ```javascript // WHERE category IN ('electronics', 'furniture', 'clothing') var products = await DBMS() .find('products') .in('category', ['electronics', 'furniture', 'clothing']) .promise(); // WHERE status IN ('active', 'pending') var users = await DBMS() .find('users') .in('status', ['active', 'pending']) .promise(); ``` #### IN con _id (ObjectIds) ```javascript // Buscar múltiples usuarios por ID var userIds = [ '507f1f77bcf86cd799439011', '507f1f77bcf86cd799439012', '507f1f77bcf86cd799439013' ]; var users = await DBMS() .find('users') .in('_id', userIds) .promise(); // icorm convierte automáticamente los strings a ObjectIds ``` #### NOTIN (excluir valores) ```javascript // WHERE status NOT IN ('deleted', 'banned') var validUsers = await DBMS() .find('users') .notin('status', ['deleted', 'banned']) .promise(); // WHERE category NOT IN ('archived') var activeProducts = await DBMS() .find('products') .notin('category', ['archived']) .promise(); ``` #### IN con Array Vacío ```javascript // Array vacío = no encuentra nada (comportamiento esperado) var users = await DBMS() .find('users') .in('_id', []) // No retorna documentos .promise(); // users = [] ``` #### Combinar IN con WHERE ```javascript // WHERE category IN (...) AND active = true var products = await DBMS() .find('products') .in('category', ['electronics', 'furniture']) .where('active', true) .where('stock', '>', 0) .promise(); ``` --- ## 📏 BETWEEN - Rangos Filtra por valores dentro de un rango. ### Sintaxis ```javascript .between(field, min, max) ``` ### Ejemplos ```javascript // WHERE age BETWEEN 18 AND 65 var users = await DBMS() .find('users') .between('age', 18, 65) .promise(); // WHERE price BETWEEN 100 AND 1000 var products = await DBMS() .find('products') .between('price', 100, 1000) .promise(); // WHERE created BETWEEN '2024-01-01' AND '2024-12-31' var thisYear = await DBMS() .find('orders') .between('created', new Date('2024-01-01'), new Date('2024-12-31')) .promise(); ``` --- ## 🔎 SEARCH - Búsqueda de Texto Búsqueda de texto con RegEx (case insensitive). ### Sintaxis ```javascript .search(field, text, [compare]) ``` **Compare:** - `'*'` - Contiene (por defecto) - `'beg'` - Comienza con - `'end'` - Termina con ### Ejemplos #### Search Básico (Contiene) ```javascript // Buscar usuarios cuyo nombre contenga 'john' (case insensitive) var users = await DBMS() .find('users') .search('name', 'john') .promise(); // Encuentra: 'John', 'JOHN', 'Johnny', 'john smith', etc. ``` #### Search con Compare ```javascript // Nombre que EMPIEZA con 'john' var users = await DBMS() .find('users') .search('name', 'john', 'beg') .promise(); // Encuentra: 'John Smith', 'Johnny', 'john' // No encuentra: 'Mary John' // Nombre que TERMINA con 'smith' var users = await DBMS() .find('users') .search('name', 'smith', 'end') .promise(); // Encuentra: 'John Smith', 'jane smith' // No encuentra: 'Smith John' ``` #### Search en Múltiples Campos ```javascript // Buscar en nombre O descripción var products = await DBMS() .find('products') .or(function(builder) { builder.search('name', 'laptop'); builder.search('description', 'laptop'); }) .promise(); ``` #### Search con Acentos ```javascript // icorm maneja automáticamente variaciones de acentos var users = await DBMS() .find('users') .search('name', 'jose') .promise(); // Encuentra: 'José', 'jose', 'JOSÉ', 'Jose' ``` --- ## 🔀 SORT - Ordenamiento Ordena los resultados. ### Sintaxis ```javascript .sort(field, [descending]) ``` **Descending:** - `false` o no especificar - Ascendente (A-Z, 0-9) - `true` - Descendente (Z-A, 9-0) ### Ejemplos #### Sort Ascendente ```javascript // ORDER BY name ASC var users = await DBMS() .find('users') .sort('name') .promise(); // ORDER BY created ASC (más antiguos primero) var oldest = await DBMS() .find('users') .sort('created') .promise(); ``` #### Sort Descendente ```javascript // ORDER BY age DESC (mayores primero) var users = await DBMS() .find('users') .sort('age', true) .promise(); // ORDER BY price DESC (más caros primero) var expensive = await DBMS() .find('products') .sort('price', true) .promise(); // ORDER BY created DESC (más recientes primero) var recent = await DBMS() .find('posts') .sort('created', true) .promise(); ``` #### Sort Múltiple ```javascript // ORDER BY active DESC, name ASC var users = await DBMS() .find('users') .sort('active', true) // Activos primero .sort('name') // Luego por nombre .promise(); // ORDER BY category ASC, price DESC var products = await DBMS() .find('products') .sort('category') // Agrupar por categoría .sort('price', true) // Más caros primero en cada categoría .promise(); ``` --- ## 📦 FIELDS - Proyección de Campos Selecciona qué campos incluir o excluir en los resultados. ### Sintaxis ```javascript .fields(field1, field2, ...) .fields('-excludedField1', '-excludedField2', ...) ``` ### Ejemplos #### Incluir Campos Específicos ```javascript // SELECT _id, name, email FROM users var users = await DBMS() .find('users') .fields('name', 'email') .promise(); // Resultado: // [ // { _id: ObjectId(...), name: 'John', email: 'john@...' }, // { _id: ObjectId(...), name: 'Jane', email: 'jane@...' } // ] // Nota: _id siempre se incluye a menos que se excluya explícitamente ``` #### Excluir Campos ```javascript // SELECT * EXCEPT (password, tokens) FROM users var users = await DBMS() .find('users') .fields('-password', '-tokens') .promise(); // Retorna todos los campos excepto password y tokens ``` #### Solo Traer IDs ```javascript // Solo _id (para verificar existencia o mapear IDs) var users = await DBMS() .find('users') .fields('_id') .where('active', true) .promise(); // Resultado: [{ _id: ObjectId(...) }, { _id: ObjectId(...) }, ...] ``` #### Campos de Objetos Anidados ```javascript // Traer solo campos específicos de objetos anidados var products = await DBMS() .find('products') .fields('name', 'price', 'specs.cpu', 'specs.ram') .promise(); // Resultado: // [ // { // _id: ObjectId(...), // name: 'Laptop', // price: 1299, // specs: { cpu: 'Intel i7', ram: '16GB' } // } // ] ``` --- ## 📄 TAKE/SKIP - Paginación Controla cuántos documentos retornar y desde dónde empezar. ### Sintaxis ```javascript .take(limit) // LIMIT .skip(offset) // OFFSET ``` ### Ejemplos #### Limitar Resultados ```javascript // Primeros 10 usuarios var users = await DBMS() .find('users') .take(10) .promise(); // Primer usuario var firstUser = await DBMS() .find('users') .sort('created') .take(1) .promise(); ``` #### Paginación Simple ```javascript // Página 1 (usuarios 1-10) var page1 = await DBMS() .find('users') .take(10) .skip(0) .promise(); // Página 2 (usuarios 11-20) var page2 = await DBMS() .find('users') .take(10) .skip(10) .promise(); // Página 3 (usuarios 21-30) var page3 = await DBMS() .find('users') .take(10) .skip(20) .promise(); ``` #### Paginación Dinámica ```javascript function paginate(page, limit) { return DBMS() .find('users') .sort('name') .take(limit) .skip((page - 1) * limit) .promise(); } // Uso var page1 = await paginate(1, 20); // Usuarios 1-20 var page2 = await paginate(2, 20); // Usuarios 21-40 var page5 = await paginate(5, 20); // Usuarios 81-100 ``` --- ## 🔀 OR - Condiciones OR Agrupa condiciones con operador OR. ### Sintaxis ```javascript .or(function(builder) { builder.where(...); builder.where(...); }) ``` ### Ejemplos #### OR Simple ```javascript // WHERE name = 'John' OR name = 'Jane' var users = await DBMS() .find('users') .or(function(builder) { builder.where('name', 'John'); builder.where('name', 'Jane'); }) .promise(); ``` #### OR con Diferentes Campos ```javascript // WHERE (age >= 65 OR status = 'premium') var users = await DBMS() .find('users') .or(function(builder) { builder.where('age', '>=', 65); builder.where('status', 'premium'); }) .promise(); ``` #### OR con AND ```javascript // WHERE active = true AND (age >= 65 OR status = 'premium') var users = await DBMS() .find('users') .where('active', true) .or(function(builder) { builder.where('age', '>=', 65); builder.where('status', 'premium'); }) .promise(); ``` #### OR con SEARCH ```javascript // WHERE (name LIKE '%john%' OR email LIKE '%john%') var users = await DBMS() .find('users') .or(function(builder) { builder.search('name', 'john'); builder.search('email', 'john'); }) .promise(); ``` --- ## ⛓️ Métodos de Encadenamiento Métodos adicionales para controlar la ejecución de queries. ### DATA - Procesar Resultados ```javascript var users = await DBMS() .find('users') .where('active', true) .data(function(users) { // Transformar datos antes de continuar users.forEach(function(user) { user.displayName = user.name + ' (' + user.email + ')'; }); }) .promise(); ``` ### CALLBACK - Usar Callbacks ```javascript DBMS() .find('users') .where('active', true) .callback(function(err, users) { if (err) { console.error('Error:', err); return; } console.log('Users:', users); }); ``` ### SET - Asignar a Variable ```javascript var db = DBMS(); await db.find('users') .where('active', true) .set('activeUsers') // Asigna resultado a db.$output.activeUsers .promise(); console.log(db.$output.activeUsers); ``` ### DEBUG - Activar Logging ```javascript var users = await DBMS() .debug() // Activa logging de la query .find('users') .where('active', true) .promise(); // Output en consola: // ICORM ---> { collection: 'mydb.users', condition: { active: true }, options: {} } ``` --- ## 🎯 Ejemplos Complejos ### Búsqueda Avanzada de Productos ```javascript async function searchProducts(filters) { var db = DBMS().find('products'); // Filtro por categorías if (filters.categories && filters.categories.length > 0) { db.in('category', filters.categories); } // Rango de precios if (filters.minPrice || filters.maxPrice) { if (filters.minPrice) db.where('price', '>=', filters.minPrice); if (filters.maxPrice) db.where('price', '<=', filters.maxPrice); } // Búsqueda de texto if (filters.search) { db.or(function(builder) { builder.search('name', filters.search); builder.search('description', filters.search); builder.search('sku', filters.search); }); } // Solo activos con stock db.where('active', true); db.where('stock', '>', 0); // Excluir campos sensibles db.fields('-cost', '-supplier'); // Ordenamiento if (filters.sortBy === 'price-asc') { db.sort('price'); } else if (filters.sortBy === 'price-desc') { db.sort('price', true); } else if (filters.sortBy === 'name') { db.sort('name'); } else { db.sort('created', true); // Más recientes primero } // Paginación var page = filters.page || 1; var limit = filters.limit || 20; db.take(limit); db.skip((page - 1) * limit); return await db.promise(); } // Uso var products = await searchProducts({ categories: ['electronics', 'computers'], minPrice: 500, maxPrice: 2000, search: 'laptop', sortBy: 'price-asc', page: 1, limit: 20 }); ``` ### Query Builder Reutilizable ```javascript function createUserQuery(baseFilters) { var db = DBMS().find('users'); // Filtros base siempre aplicados db.where('deleted', false); if (baseFilters.active !== undefined) { db.where('active', baseFilters.active); } return db; } // Uso var activeUsers = await createUserQuery({ active: true }) .where('age', '>=', 18) .sort('name') .promise(); var inactiveAdmins = await createUserQuery({ active: false }) .where('role', 'admin') .sort('created', true) .promise(); ``` ### Búsqueda con Múltiples Filtros Opcionales ```javascript async function findUsers(criteria) { var db = DBMS().find('users'); // WHERE dinámico Object.keys(criteria).forEach(function(key) { var value = criteria[key]; if (value !== undefined && value !== null && value !== '') { if (key === 'search') { // Búsqueda de texto en múltiples campos db.or(function(builder) { builder.search('name', value); builder.search('email', value); }); } else if (key === 'minAge') { db.where('age', '>=', value); } else if (key === 'maxAge') { db.where('age', '<=', value); } else if (key === 'roles' && Array.isArray(value)) { db.in('role', value); } else { db.where(key, value); } } }); return await db.promise(); } // Uso var results = await findUsers({ active: true, minAge: 18, maxAge: 65, search: 'john', roles: ['admin', 'moderator'] }); ``` --- [← Volver al Índice](./README.md) | [Siguiente: Operadores →](./mongodb-operators.md)