mongoose-smart-query 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -13
- package/dist/mongoose-smart-query.d.ts +15 -12
- package/dist/mongoose-smart-query.js +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -85,23 +85,74 @@ const result = await Person.smartQuery<IPerson>(req.query)
|
|
|
85
85
|
// Result: IPerson[]
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
+
### Searching (Autocomplete and Text Search)
|
|
89
|
+
|
|
90
|
+
`mongoose-smart-query` provides two built-in ways to search your collections based on the incoming query object (e.g., `req.query`).
|
|
91
|
+
|
|
92
|
+
1. **Autocomplete/Regex Search (`$q`)**:
|
|
93
|
+
When the `$q` parameter is present in the query, the plugin performs an autocomplete search. To define which fields are searchable via autocomplete, set the `fieldsForDefaultQuery` plugin option.
|
|
94
|
+
- If `fieldsForDefaultQuery` contains a single field, it performs a highly-optimized single-field `$regex` search.
|
|
95
|
+
- If it contains space-separated fields (e.g., `'name email'`), it performs an `$or` `$regex` search across them.
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// req.query = { $q: 'john' }
|
|
99
|
+
const result = await Person.smartQuery(req.query)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
2. **MongoDB Native Text Search (`$text`)**:
|
|
103
|
+
If your schema has a `text` index (`schema.index({ name: 'text' })`), you can use the `$text` parameter to perform explicit full-text searches. This uses MongoDB's native `$text` operator, sorting results by `$meta` text score automatically.
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
// req.query = { $text: 'developer' }
|
|
107
|
+
const result = await Person.smartQuery(req.query)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Normalizing Search Text
|
|
111
|
+
|
|
112
|
+
Searching for text with accents or special characters can often miss results if the database fields are not normalized (e.g., searching for "José" vs "jose").
|
|
113
|
+
|
|
114
|
+
`mongoose-smart-query` exports a utility function, `normalizeSearchText`, which converts text to lowercase, removes diacritics/accents, and removes non-alphanumeric characters. You can use it in your pre-save Mongoose hooks to keep a "searchable" field clean in your documents.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { normalizeSearchText } from 'mongoose-smart-query'
|
|
118
|
+
|
|
119
|
+
PersonSchema.pre('save', function (next) {
|
|
120
|
+
// Create a clean, concatenated string for optimized regex autocomplete
|
|
121
|
+
this.searchString = normalizeSearchText([this.name, this.surname])
|
|
122
|
+
next()
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
You can then instruct the plugin to automatically normalize the user's incoming `$q` search parameter to match your cleaned document fields by enabling `normalizeSearchQuery: true`:
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
PersonSchema.plugin(mongooseSmartQuery, {
|
|
130
|
+
fieldsForDefaultQuery: 'searchString', // Point autocomplete to your combined field
|
|
131
|
+
normalizeSearchQuery: true, // Automatically applies normalizeSearchText to req.query.$q
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
By combining a single normalized `searchString` field and `normalizeSearchQuery: true`, MongoDB can evaluate your autocomplete searches with optimum efficiency, bypassing the `$and` and case-insensitive (`i`) regex overhead.
|
|
136
|
+
|
|
88
137
|
## Plugin Configuration
|
|
89
138
|
|
|
90
139
|
These options are passed to the plugin during registration: `schema.plugin(mongooseSmartQuery, options)`.
|
|
91
140
|
|
|
92
|
-
| Key | Description
|
|
93
|
-
| ----------------------- |
|
|
94
|
-
| `protectedFields` | Fields that should not be included in the query results
|
|
95
|
-
| `defaultFields` | Fields included in the default query results
|
|
96
|
-
| `defaultSort` | Default sorting
|
|
97
|
-
| `defaultLimit` | Number of documents per query
|
|
98
|
-
| `fieldsForDefaultQuery` |
|
|
99
|
-
| `pageQueryName` | Key for pagination param in query object
|
|
100
|
-
| `limitQueryName` | Key for limit param in query object
|
|
101
|
-
| `fieldsQueryName` | Key to project specific fields
|
|
102
|
-
| `sortQueryName` | Key for sorting param
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
141
|
+
| Key | Description | Default |
|
|
142
|
+
| ----------------------- | -------------------------------------------------------------------------- | ----------- |
|
|
143
|
+
| `protectedFields` | Fields that should not be included in the query results | `''` |
|
|
144
|
+
| `defaultFields` | Fields included in the default query results | `'_id'` |
|
|
145
|
+
| `defaultSort` | Default sorting | `'-id'` |
|
|
146
|
+
| `defaultLimit` | Number of documents per query | `20` |
|
|
147
|
+
| `fieldsForDefaultQuery` | Fields to perform `$regex` autocomplete search when `queryName` is present | `''` |
|
|
148
|
+
| `pageQueryName` | Key for pagination param in query object | `'$page'` |
|
|
149
|
+
| `limitQueryName` | Key for limit param in query object | `'$limit'` |
|
|
150
|
+
| `fieldsQueryName` | Key to project specific fields | `'$fields'` |
|
|
151
|
+
| `sortQueryName` | Key for sorting param | `$sort` |
|
|
152
|
+
| `queryName` | Key for regex autocomplete search param | `'$q'` |
|
|
153
|
+
| `textQueryName` | Key for explicit MongoDB `$text` index search param | `'$text'` |
|
|
154
|
+
| `normalizeSearchQuery` | Applies `normalizeSearchText` to `$q` automatically | `false` |
|
|
155
|
+
| `unwindName` | Key for unwind param | `'$unwind'` |
|
|
105
156
|
|
|
106
157
|
## Method Options
|
|
107
158
|
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { Schema, PipelineStage } from 'mongoose';
|
|
2
|
+
/**
|
|
3
|
+
* Normalizes text for search indexing and querying.
|
|
4
|
+
* Converts to lowercase, removes diacritics/accents, and removes any non-alphanumeric character (except the spacer).
|
|
5
|
+
* Multiple spaces/spacers are collapsed into one.
|
|
6
|
+
* @param input String or array of strings to concatenate and normalize.
|
|
7
|
+
* @param spacer String used to join array values or replace spaces. Default is ' '.
|
|
8
|
+
* @returns The normalized string.
|
|
9
|
+
*/
|
|
10
|
+
export declare function normalizeSearchText(input: string | Array<string | undefined>, spacer?: string, maxSearchLength?: number): string;
|
|
2
11
|
interface SmartQueryOptions {
|
|
3
12
|
prePipeline?: PipelineStage[];
|
|
4
13
|
autoPaginate?: boolean;
|
|
@@ -40,8 +49,7 @@ interface PluginOptions {
|
|
|
40
49
|
*/
|
|
41
50
|
defaultLimit?: number;
|
|
42
51
|
/**
|
|
43
|
-
* What fields to look for when making a query. Default: `''`.
|
|
44
|
-
* @deprecated Use `defaultFields` instead.
|
|
52
|
+
* What fields to look for when making a default search query. Default: `''`.
|
|
45
53
|
*/
|
|
46
54
|
fieldsForDefaultQuery?: string;
|
|
47
55
|
/**
|
|
@@ -62,7 +70,6 @@ interface PluginOptions {
|
|
|
62
70
|
sortQueryName?: string;
|
|
63
71
|
/**
|
|
64
72
|
* Key for search. Default: `'$q'`.
|
|
65
|
-
* @deprecated `queryName` is deprecated, use `searchQueryName` instead.
|
|
66
73
|
*/
|
|
67
74
|
queryName?: string;
|
|
68
75
|
/**
|
|
@@ -74,17 +81,13 @@ interface PluginOptions {
|
|
|
74
81
|
*/
|
|
75
82
|
allFieldsQueryName?: string;
|
|
76
83
|
/**
|
|
77
|
-
*
|
|
78
|
-
*/
|
|
79
|
-
getAllFieldsByDefault?: boolean;
|
|
80
|
-
/**
|
|
81
|
-
* Fields to search by default
|
|
84
|
+
* Key for specific text index search (MongoDB $text). Default: `'$text'`.
|
|
82
85
|
*/
|
|
83
|
-
|
|
86
|
+
textQueryName?: string;
|
|
84
87
|
/**
|
|
85
|
-
*
|
|
88
|
+
* If true, applies `normalizeSearchText` to the `$q` search value before executing the query. Default: `false`.
|
|
86
89
|
*/
|
|
87
|
-
|
|
90
|
+
normalizeSearchQuery?: boolean;
|
|
88
91
|
}
|
|
89
92
|
interface TObject {
|
|
90
93
|
[value: string]: any;
|
|
@@ -104,5 +107,5 @@ export declare function stringToQuery(query?: string, value?: string): object;
|
|
|
104
107
|
* @returns The object without the keys
|
|
105
108
|
*/
|
|
106
109
|
export declare function removeKeys(initial: TObject, toRemove: TObject): TObject;
|
|
107
|
-
export default function (schema: Schema, { protectedFields, defaultFields, defaultSort, defaultLimit, pageQueryName, limitQueryName, fieldsQueryName, sortQueryName, queryName,
|
|
110
|
+
export default function (schema: Schema, { protectedFields, defaultFields, defaultSort, defaultLimit, fieldsForDefaultQuery, pageQueryName, limitQueryName, fieldsQueryName, sortQueryName, queryName, textQueryName, unwindName, allFieldsQueryName, normalizeSearchQuery, }: PluginOptions): void;
|
|
108
111
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var __assign=this&&this.__assign||function(){return(__assign=Object.assign||function(e){for(var t,r=1,n=arguments.length;r<n;r++)for(var i in t=arguments[r])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)},__awaiter=this&&this.__awaiter||function(e,a,s,c){return new(s=s||Promise)(function(r,t){function n(e){try{o(c.next(e))}catch(e){t(e)}}function i(e){try{o(c.throw(e))}catch(e){t(e)}}function o(e){var t;e.done?r(e.value):((t=e.value)instanceof s?t:new s(function(e){e(t)})).then(n,i)}o((c=c.apply(e,a||[])).next())})},__generator=this&&this.__generator||function(n,i){var o,a,s,c={label:0,sent:function(){if(1&s[0])throw s[1];return s[1]},trys:[],ops:[]},u=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return u.next=e(0),u.throw=e(1),u.return=e(2),"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function e(r){return function(e){var t=[r,e];if(o)throw new TypeError("Generator is already executing.");for(;c=u&&t[u=0]?0:c;)try{if(o=1,a&&(s=2&t[0]?a.return:t[0]?a.throw||((s=a.return)&&s.call(a),0):a.next)&&!(s=s.call(a,t[1])).done)return s;switch(a=0,(t=s?[2&t[0],s.value]:t)[0]){case 0:case 1:s=t;break;case 4:return c.label++,{value:t[1],done:!1};case 5:c.label++,a=t[1],t=[0];continue;case 7:t=c.ops.pop(),c.trys.pop();continue;default:if(!(s=0<(s=c.trys).length&&s[s.length-1])&&(6===t[0]||2===t[0])){c=0;continue}if(3===t[0]&&(!s||t[1]>s[0]&&t[1]<s[3]))c.label=t[1];else if(6===t[0]&&c.label<s[1])c.label=s[1],s=t;else{if(!(s&&c.label<s[2])){s[2]&&c.ops.pop(),c.trys.pop();continue}c.label=s[2],c.ops.push(t)}}t=i.call(n,c)}catch(e){t=[6,e],a=0}finally{o=s=0}if(5&t[0])throw t[1];return{value:t[0]?t[1]:void 0,done:!0}}}},__spreadArray=this&&this.__spreadArray||function(e,t,r){if(r||2===arguments.length)for(var n,i=0,o=t.length;i<o;i++)!n&&i in t||((n=n||Array.prototype.slice.call(t,0,i))[i]=t[i]);return e.concat(n||Array.prototype.slice.call(t))},mongoose_1=(Object.defineProperty(exports,"__esModule",{value:!0}),exports.stringToQuery=stringToQuery,exports.removeKeys=removeKeys,exports.default=default_1,require("mongoose")),reemplazarSubdoc=function(e,t,r){var n,i;r&&(n=e,(i=t.split(".")).forEach(function(e,t){t===i.length-1?null!=n&&n[e]&&(n[e]=r):n=null==n?void 0:n[e]}))},getCampo=function(e,t){var r=e;return t.split(".").forEach(function(e){return r=null==r?void 0:r[e]}),r};function stringToQuery(e,o){void 0===o&&(o="1");e=(e=void 0===e?"":e).replace(/(})(?!$| *})|([\w.]+)(?= *{)|([\w.]+)(?=$| *})|([\w.]+)/g,function(e,t,r,n,i){return t?t+",":r?'"'.concat(r,'":'):n?'"'.concat(n,'": ').concat(o):i?'"'.concat(i,'": ').concat(o,","):""});return JSON.parse("{ ".concat(e," }"))}var parseValue=function(e,t){switch(t){case"ObjectID":case"ObjectId":return new mongoose_1.Types.ObjectId(e);case"Date":return new Date(e);case"Number":return Number(e);case"Boolean":return"boolean"==typeof e?e:"true"===e;default:return e}};function removeKeys(e,t){var r,n=__assign({},e);for(r in t)!n[r]||"object"==typeof t[r]&&(n[r]=removeKeys(n[r],t[r]),0!==Object.keys(n[r]).length)||delete n[r];return n}function default_1(O,e){function A(i,o){function a(t,e,r){var n=s.find(function(e){return e.field===t});n?n.project=__assign(__assign({},n.project),r):s.push({field:t,from:e,project:r})}(o=void 0===o?"":o)&&(o+=".");var e,s=[];for(e in i=void 0===i?{}:i)(e=>{var t,r,n;if("object"!=typeof i[e])return(e.includes(".")||o)&&(t=e.split(/\.(.+)/),r=O.path(o+t[0]))&&r.options.ref&&((n=s.find(function(e){return e.field===t[0]}))?n.project[t[1]]=1:s.push({field:t[0],from:r.options.ref,project:((n={})[t[1]]=1,n)}));(r=O.path(o+e))&&r.options.ref?a(o+e,r.options.ref,i[e]):A(i[e],o+e).forEach(function(e){a(e.field,e.from,e.project)})})(e);return s}var t=e.protectedFields,S=void 0===t?"":t,t=e.defaultFields,Q=void 0===t?"_id":t,t=e.defaultSort,k=void 0===t?"-_id":t,t=e.defaultLimit,N=void 0===t?20:t,t=e.pageQueryName,P=void 0===t?"$page":t,t=e.limitQueryName,T=void 0===t?"$limit":t,t=e.fieldsQueryName,I=void 0===t?"$fields":t,t=e.sortQueryName,C=void 0===t?"$sort":t,t=e.queryName,E=void 0===t?"$q":t,t=e.unwindName,F=void 0===t?"$unwind":t,t=e.fieldsForDefaultQuery,z=void 0===t?"":t,t=e.allFieldsQueryName,D=void 0===t?"$getAllFields":t,t=e.fieldsForDefaultSearch,G=void 0===t?[]:t,t=e.searchQueryName,K=void 0===t?"$search":t,t=e.getAllFieldsByDefault,q=void 0!==t&&t,V=stringToQuery(S);O.statics.smartQuery=function(){return __awaiter(this,arguments,void 0,function(t,r){var n,i,o,a,s,c,u,l,p,f,d,h,_,g,v,y,m,$,b,w,j=this;return void 0===t&&(t={}),void 0===r&&(r={}),__generator(this,function(e){switch(e.label){case 0:return(n=r.prePipeline,n=void 0===n?[]:n,i=r.autoPaginate,o=[],a=null,i=void 0!==i&&i)?(c=this.__smartQueryGetPipeline(__assign({},t),!1,n).then(function(e){return __awaiter(j,[e],void 0,function(e){var t,r=e.pipeline,n=e.lookupsConfirmados;return __generator(this,function(e){switch(e.label){case 0:return t={},[4,this.aggregate(r)];case 1:return[2,(t.docs=e.sent(),t.lookups=n,t)]}})})}),u=this.__smartQueryGetPipeline(__assign({},t),!0,n).then(function(e){e=e.pipeline;return j.aggregate(e)}),[4,Promise.all([c,u])]):[3,2];case 1:return c=e.sent(),u=c[0],w=c[1],o=u.docs,s=u.lookups,w=(null==(w=w[0])?void 0:w.size)||0,f=parseInt(t[P])||1,l=parseInt(t[T])||N,p=Math.ceil(w/l),a={total:w,page:f,pages:p,limit:l},[3,5];case 2:return[4,this.__smartQueryGetPipeline(__assign({},t),!1,n)];case 3:return w=e.sent(),f=w.pipeline,s=w.lookupsConfirmados,[4,this.aggregate(f)];case 4:o=e.sent(),e.label=5;case 5:return d=t.business?{business:new mongoose_1.Types.ObjectId(t.business)}:{},[4,Promise.all(s.map(function(r){var e=o.reduce(function(e,t){t=getCampo(t,r.field);return t&&e.push(t),e},[]);return 0!==e.length?mongoose_1.connection.collection(r.from).find(__assign({_id:{$in:e}},d)).project(r.project).toArray():[]}))];case 6:for(_ in h=e.sent(),s)for(g=h[_],v=s[_],y=function(e){var t=getCampo(e,v.field);t&&reemplazarSubdoc(e,v.field,g.find(function(e){return e._id.equals(t)}))},m=0,$=o;m<$.length;m++)b=$[m],y(b);return i?[2,{data:o,pagination:a}]:[2,o]}})})},O.statics.smartCount=function(){return __awaiter(this,arguments,void 0,function(t){var r;return void 0===t&&(t={}),__generator(this,function(e){switch(e.label){case 0:return[4,this.__smartQueryGetPipeline(__assign({},t),!0)];case 1:return r=e.sent().pipeline,[4,this.aggregate(r)];case 2:return[2,0===(r=e.sent()).length?0:r[0].size]}})})},O.statics.__smartQueryGetPipeline=function(e){return __awaiter(this,arguments,void 0,function(w,s,c){var _,g,u,l,p,v,f,d,h,y,m,$,b,j,x=this;return void 0===s&&(s=!1),void 0===c&&(c=[]),__generator(this,function(e){switch(e.label){case 0:return _=this.schema.indexes().some(function(e){e=e[0];return Object.values(e).includes("text")}),g=w.business?{business:new mongoose_1.Types.ObjectId(w.business)}:{},u=JSON.parse(JSON.stringify(w)),l=parseInt(w[P])||1,p=parseInt(w[T])||N,v=function(){return __awaiter(x,void 0,void 0,function(){var m,$,b,t,r,n=this;return __generator(this,function(e){switch(e.label){case 0:for(r in m={},$={},b=[],t=function(e){var t,r=O.path(e);if(!r&&!e.includes("."))return"continue";var n,i,o=e,a=void 0,s=w[o],e=(e.includes(".")&&(f=(e=e.split("."))[0],e=e[1],n=O.path(f))&&n.options.ref&&(o=e,$[a=f]={collection:n.options.ref,$match:{}}),a?$[a].$match:m),c=/(?:\{(\$?[\w ]+)\})?([^{}\n]+)/g,u=[];if("string"==typeof s){var l={},p=s,f=p.startsWith("{$or}");for(f&&(p=p.replace("{$or}",""));null!==(i=c.exec(p));)u.push([i[0],i[1],i[2]]);for(var d=0,h=u;d<h.length;d++){var _=h[d],g=_[1],v=_[2];switch(g){case"$exists":l[o]={$exists:"false"!==v};break;case"$includes":l[o]={$regex:RegExp(v.replace(/[^\w]/g,"."),"i")};break;case"$in":case"$nin":var y=v.split(",").map(function(e){return parseValue(e.trim(),null==r?void 0:r.instance)});l[o]=((t={})[g]=y,t);break;default:y=parseValue(v,null==r?void 0:r.instance);g?"object"==typeof l[o]?l[o][g]=y:l[o]=((t={})[g]=y,t):"string"==typeof v&&v.includes("$exists")?l[o]={$exists:!0,$ne:[]}:l[o]=y}}f?b.push(l):Object.assign(e,l)}else e[o]=parseValue(s,null==r?void 0:r.instance)},w)t(r);return 0!==b.length&&(m.$or=b),0===Object.keys($).length?[3,2]:[4,Promise.all(Object.entries($).map(function(e){return __awaiter(n,[e],void 0,function(e){var t,r=e[0],n=e[1];return __generator(this,function(e){switch(e.label){case 0:return[4,mongoose_1.connection.collection(n.collection).find(__assign(__assign({},n.$match),g)).project({_id:1}).toArray()];case 1:return t=e.sent(),m[r]={$in:t.map(function(e){return e._id})},[2]}})})}))];case 1:e.sent(),e.label=2;case 2:return[2,m]}})})},f=function(){return w[F]?[{$unwind:{path:"$".concat(w[F]),preserveNullAndEmptyArrays:!0}}]:[]},[4,function(){return __awaiter(x,void 0,void 0,function(){var o,a,t,s,c,r,n,i,u,l,p,f,d,h=this;return __generator(this,function(e){switch(e.label){case 0:return(o={},t=!(a={}),_&&w[E])?(o={$text:{$search:w[E]}},t=!0,[3,3]):[3,1];case 1:if(!w[E]||!z)return[3,3];for(p=z.split(" "),l=w[E].replace(/[()[\\\]]/g,".").replace(/[+]/g,"\\+").replace(/[*]/g,"\\*"),s=l.split(" "),c={$regex:RegExp(l,"i")},r=function(r){var e,t,n,i;O.path(r)?(o.$or||(o.$or=[]),0===s.length?o.$or.push(((n={})[r]=c,n)):o.$or.push({$and:s.map(function(e){var t={};return t[r]={$regex:RegExp(e,"i")},t})})):r.includes(".")&&(t=(n=r.split("."))[0],n=n[1],i=O.path(t))&&i.options.ref&&(a[t]?a[t].$match.$or.push(((e={})[n]=c,e)):a[t]={collection:i.options.ref,$match:{$or:[((e={})[n]=c,e)]}})},n=0,i=p;n<i.length;n++)u=i[n],r(u);return 0===Object.keys(a).length?[3,3]:[4,Promise.all(Object.entries(a).map(function(e){return __awaiter(h,[e],void 0,function(e){var t,r,n=e[0],i=e[1];return __generator(this,function(e){switch(e.label){case 0:return[4,mongoose_1.connection.collection(i.collection).find(__assign(__assign({},i.$match),g)).project({_id:1}).toArray()];case 1:return t=e.sent(),(t=t.map(function(e){return e._id})).length&&o.$or.push(((r={})[n]={$in:t},r)),[2]}})})}))];case 2:e.sent(),e.label=3;case 3:return w[K]&&0!==G.length&&(l=Array.isArray(G)?G:[G],1===(p=l.map(function(e){var t={};return t[e]={$regex:w[K].toLowerCase().replace(/[^a-z0-9]/g,"")},t})).length?o=p[0]:o.$or=p),[4,v()];case 4:return f=e.sent(),(d=f.$or)&&(delete f.$or,Array.isArray(o.$or)?o.$or=o.$or.concat(d):o.$or=d),[2,{match:__assign(__assign({},f),o),usingTextSearch:t}]}})})}()];case 1:if(h=e.sent(),$=h.match,d=h.usingTextSearch,!(a=w)[I]&&Q&&(a[I]=Q),h=removeKeys(stringToQuery(a[I]),V),y=A(h),m=[],0!==Object.keys($).length&&m.push({$match:$}),m.push.apply(m,c),s)m.push.apply(m,__spreadArray(__spreadArray([],f(),!1),[{$count:"size"}],!1));else{if($=function(){if(d)return{$localSort:{score:{$meta:"textScore"},_id:-1}};if(!w[C]){if(!k)return{};w[C]=k}for(var e=/(-)?([\w.]+)/g,t={},r={};null!==(i=e.exec(w[C]));){var n=i[1],i=i[2];!!O.path(i)?t[i]=n?-1:1:r[i]=n?-1:1}return{$localSort:0!==Object.keys(t).length?t:void 0,$foreignSort:0!==Object.keys(r).length?r:void 0}}(),b=[],!u[I]&&!0===q||"true"===(null==(j=w[D])?void 0:j.toString()))S&&b.push({$project:stringToQuery(S,"0")}),d&&b.push({$addFields:{score:{$meta:"textScore"}}});else{var t=h;void 0===t&&(t={});for(var r=0,n=y;r<n.length;r++){var i=n[r];if(i.field.includes(".")||t[i.field])reemplazarSubdoc(t,i.field,1);else for(var o in t)o.startsWith(i.field+".")&&(delete t[o],t[i.field]=1)}j=__assign({},h),d&&(j.score={$meta:"textScore"}),b.push({$project:j})}m.push.apply(m,__spreadArray(__spreadArray(__spreadArray(__spreadArray([],$.$localSort?[{$sort:$.$localSort}]:[],!1),f(),!1),[{$skip:(l-1)*p},{$limit:p}],!1),b,!1))}return[2,{pipeline:m,lookupsConfirmados:y}]}var a})})}}
|
|
1
|
+
var __assign=this&&this.__assign||function(){return(__assign=Object.assign||function(e){for(var t,r=1,n=arguments.length;r<n;r++)for(var i in t=arguments[r])Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e}).apply(this,arguments)},__awaiter=this&&this.__awaiter||function(e,a,s,c){return new(s=s||Promise)(function(r,t){function n(e){try{o(c.next(e))}catch(e){t(e)}}function i(e){try{o(c.throw(e))}catch(e){t(e)}}function o(e){var t;e.done?r(e.value):((t=e.value)instanceof s?t:new s(function(e){e(t)})).then(n,i)}o((c=c.apply(e,a||[])).next())})},__generator=this&&this.__generator||function(n,i){var o,a,s,c={label:0,sent:function(){if(1&s[0])throw s[1];return s[1]},trys:[],ops:[]},u=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return u.next=e(0),u.throw=e(1),u.return=e(2),"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function e(r){return function(e){var t=[r,e];if(o)throw new TypeError("Generator is already executing.");for(;c=u&&t[u=0]?0:c;)try{if(o=1,a&&(s=2&t[0]?a.return:t[0]?a.throw||((s=a.return)&&s.call(a),0):a.next)&&!(s=s.call(a,t[1])).done)return s;switch(a=0,(t=s?[2&t[0],s.value]:t)[0]){case 0:case 1:s=t;break;case 4:return c.label++,{value:t[1],done:!1};case 5:c.label++,a=t[1],t=[0];continue;case 7:t=c.ops.pop(),c.trys.pop();continue;default:if(!(s=0<(s=c.trys).length&&s[s.length-1])&&(6===t[0]||2===t[0])){c=0;continue}if(3===t[0]&&(!s||t[1]>s[0]&&t[1]<s[3]))c.label=t[1];else if(6===t[0]&&c.label<s[1])c.label=s[1],s=t;else{if(!(s&&c.label<s[2])){s[2]&&c.ops.pop(),c.trys.pop();continue}c.label=s[2],c.ops.push(t)}}t=i.call(n,c)}catch(e){t=[6,e],a=0}finally{o=s=0}if(5&t[0])throw t[1];return{value:t[0]?t[1]:void 0,done:!0}}}},__spreadArray=this&&this.__spreadArray||function(e,t,r){if(r||2===arguments.length)for(var n,i=0,o=t.length;i<o;i++)!n&&i in t||((n=n||Array.prototype.slice.call(t,0,i))[i]=t[i]);return e.concat(n||Array.prototype.slice.call(t))},mongoose_1=(Object.defineProperty(exports,"__esModule",{value:!0}),exports.normalizeSearchText=normalizeSearchText,exports.stringToQuery=stringToQuery,exports.removeKeys=removeKeys,exports.default=default_1,require("mongoose"));function normalizeSearchText(e,t,r){var n;return void 0===t&&(t=" "),void 0===r&&(r=900),e?(n=function(e){return e.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g,"").replace(/[^a-z0-9 ]/g,"").trim().replace(/\s+/g,t)},Array.isArray(e)?e.map(function(e){return e?n(e):""}).filter(Boolean).join(t):n(e).substring(0,r)):""}var reemplazarSubdoc=function(e,t,r){var n,i;r&&(n=e,(i=t.split(".")).forEach(function(e,t){t===i.length-1?null!=n&&n[e]&&(n[e]=r):n=null==n?void 0:n[e]}))},getCampo=function(e,t){var r=e;return t.split(".").forEach(function(e){return r=null==r?void 0:r[e]}),r};function stringToQuery(e,o){void 0===o&&(o="1");e=(e=void 0===e?"":e).replace(/(})(?!$| *})|([\w.]+)(?= *{)|([\w.]+)(?=$| *})|([\w.]+)/g,function(e,t,r,n,i){return t?t+",":r?'"'.concat(r,'":'):n?'"'.concat(n,'": ').concat(o):i?'"'.concat(i,'": ').concat(o,","):""});return JSON.parse("{ ".concat(e," }"))}var parseValue=function(e,t){switch(t){case"ObjectID":case"ObjectId":return new mongoose_1.Types.ObjectId(e);case"Date":return new Date(e);case"Number":return Number(e);case"Boolean":return"boolean"==typeof e?e:"true"===e;default:return e}};function removeKeys(e,t){var r,n=__assign({},e);for(r in t)!n[r]||"object"==typeof t[r]&&(n[r]=removeKeys(n[r],t[r]),0!==Object.keys(n[r]).length)||delete n[r];return n}function default_1(j,e){function S(i,o){function a(t,e,r){var n=s.find(function(e){return e.field===t});n?n.project=__assign(__assign({},n.project),r):s.push({field:t,from:e,project:r})}(o=void 0===o?"":o)&&(o+=".");var e,s=[];for(e in i=void 0===i?{}:i)(e=>{var t,r,n;if("object"!=typeof i[e])return(e.includes(".")||o)&&(t=e.split(/\.(.+)/),r=j.path(o+t[0]))&&r.options.ref&&((n=s.find(function(e){return e.field===t[0]}))?n.project[t[1]]=1:s.push({field:t[0],from:r.options.ref,project:((n={})[t[1]]=1,n)}));(r=j.path(o+e))&&r.options.ref?a(o+e,r.options.ref,i[e]):S(i[e],o+e).forEach(function(e){a(e.field,e.from,e.project)})})(e);return s}var t=e.protectedFields,O=void 0===t?"":t,t=e.defaultFields,A=void 0===t?"_id":t,t=e.defaultSort,Q=void 0===t?"-_id":t,t=e.defaultLimit,k=void 0===t?20:t,t=e.fieldsForDefaultQuery,T=void 0===t?"":t,t=e.pageQueryName,P=void 0===t?"$page":t,t=e.limitQueryName,z=void 0===t?"$limit":t,t=e.fieldsQueryName,N=void 0===t?"$fields":t,t=e.sortQueryName,I=void 0===t?"$sort":t,t=e.queryName,E=void 0===t?"$q":t,t=e.textQueryName,C=void 0===t?"$text":t,t=e.unwindName,F=void 0===t?"$unwind":t,t=e.allFieldsQueryName,G=void 0===t?"$getAllFields":t,t=e.normalizeSearchQuery,D=void 0!==t&&t,K=stringToQuery(O);j.statics.smartQuery=function(){return __awaiter(this,arguments,void 0,function(t,r){var n,i,o,a,s,c,u,l,p,f,d,h,_,g,v,m,y,$,b,w,x=this;return void 0===t&&(t={}),void 0===r&&(r={}),__generator(this,function(e){switch(e.label){case 0:return(n=r.prePipeline,n=void 0===n?[]:n,i=r.autoPaginate,o=[],a=null,i=void 0!==i&&i)?(c=this.__smartQueryGetPipeline(__assign({},t),!1,n).then(function(e){return __awaiter(x,[e],void 0,function(e){var t,r=e.pipeline,n=e.lookupsConfirmados;return __generator(this,function(e){switch(e.label){case 0:return t={},[4,this.aggregate(r)];case 1:return[2,(t.docs=e.sent(),t.lookups=n,t)]}})})}),u=this.__smartQueryGetPipeline(__assign({},t),!0,n).then(function(e){e=e.pipeline;return x.aggregate(e)}),[4,Promise.all([c,u])]):[3,2];case 1:return c=e.sent(),u=c[0],w=c[1],o=u.docs,s=u.lookups,w=(null==(w=w[0])?void 0:w.size)||0,f=parseInt(t[P])||1,l=parseInt(t[z])||k,p=Math.ceil(w/l),a={total:w,page:f,pages:p,limit:l},[3,5];case 2:return[4,this.__smartQueryGetPipeline(__assign({},t),!1,n)];case 3:return w=e.sent(),f=w.pipeline,s=w.lookupsConfirmados,[4,this.aggregate(f)];case 4:o=e.sent(),e.label=5;case 5:return d=t.business?{business:new mongoose_1.Types.ObjectId(t.business)}:{},[4,Promise.all(s.map(function(r){var e=o.reduce(function(e,t){t=getCampo(t,r.field);return t&&e.push(t),e},[]);return 0!==e.length?mongoose_1.connection.collection(r.from).find(__assign({_id:{$in:e}},d)).project(r.project).toArray():[]}))];case 6:for(_ in h=e.sent(),s)for(g=h[_],v=s[_],m=function(e){var t=getCampo(e,v.field);t&&reemplazarSubdoc(e,v.field,g.find(function(e){return e._id.equals(t)}))},y=0,$=o;y<$.length;y++)b=$[y],m(b);return i?[2,{data:o,pagination:a}]:[2,o]}})})},j.statics.smartCount=function(){return __awaiter(this,arguments,void 0,function(t){var r;return void 0===t&&(t={}),__generator(this,function(e){switch(e.label){case 0:return[4,this.__smartQueryGetPipeline(__assign({},t),!0)];case 1:return r=e.sent().pipeline,[4,this.aggregate(r)];case 2:return[2,0===(r=e.sent()).length?0:r[0].size]}})})},j.statics.__smartQueryGetPipeline=function(e){return __awaiter(this,arguments,void 0,function(w,s,c){var _,g,u,l,v,p,f,d,h,m,y,$,b,x=this;return void 0===s&&(s=!1),void 0===c&&(c=[]),__generator(this,function(e){switch(e.label){case 0:return _=this.schema.indexes().some(function(e){e=e[0];return Object.values(e).includes("text")}),g=w.business?{business:new mongoose_1.Types.ObjectId(w.business)}:{},u=parseInt(w[P])||1,l=parseInt(w[z])||k,v=function(){return __awaiter(x,void 0,void 0,function(){var y,$,b,t,r,n=this;return __generator(this,function(e){switch(e.label){case 0:for(r in y={},$={},b=[],t=function(e){var t,r=j.path(e);if(!r&&!e.includes("."))return"continue";var n,i,o=e,a=void 0,s=w[o],e=(e.includes(".")&&(f=(e=e.split("."))[0],e=e[1],n=j.path(f))&&n.options.ref&&(o=e,$[a=f]={collection:n.options.ref,$match:{}}),a?$[a].$match:y),c=/(?:\{(\$?[\w ]+)\})?([^{}\n]+)/g,u=[];if("string"==typeof s){var l={},p=s,f=p.startsWith("{$or}");for(f&&(p=p.replace("{$or}",""));null!==(i=c.exec(p));)u.push([i[0],i[1],i[2]]);for(var d=0,h=u;d<h.length;d++){var _=h[d],g=_[1],v=_[2];switch(g){case"$exists":l[o]={$exists:"false"!==v};break;case"$includes":l[o]={$regex:RegExp(v.replace(/[^\w]/g,"."),"i")};break;case"$in":case"$nin":var m=v.split(",").map(function(e){return parseValue(e.trim(),null==r?void 0:r.instance)});l[o]=((t={})[g]=m,t);break;default:m=parseValue(v,null==r?void 0:r.instance);g?"object"==typeof l[o]?l[o][g]=m:l[o]=((t={})[g]=m,t):"string"==typeof v&&v.includes("$exists")?l[o]={$exists:!0,$ne:[]}:l[o]=m}}f?b.push(l):Object.assign(e,l)}else e[o]=parseValue(s,null==r?void 0:r.instance)},w)t(r);return 0!==b.length&&(y.$or=b),0===Object.keys($).length?[3,2]:[4,Promise.all(Object.entries($).map(function(e){return __awaiter(n,[e],void 0,function(e){var t,r=e[0],n=e[1];return __generator(this,function(e){switch(e.label){case 0:return[4,mongoose_1.connection.collection(n.collection).find(__assign(__assign({},n.$match),g)).project({_id:1}).toArray()];case 1:return t=e.sent(),y[r]={$in:t.map(function(e){return e._id})},[2]}})})}))];case 1:e.sent(),e.label=2;case 2:return[2,y]}})})},p=function(){return w[F]?[{$unwind:{path:"$".concat(w[F]),preserveNullAndEmptyArrays:!0}}]:[]},[4,function(){return __awaiter(x,void 0,void 0,function(){var o,a,t,s,c,u,r,n,i,l,p,f,d,h=this;return __generator(this,function(e){switch(e.label){case 0:return(o={},t=!(a={}),_&&w[C])?(o={$text:{$search:w[C]}},t=!0,[3,3]):[3,1];case 1:if(!w[E]||!T)return[3,3];if(f=T.split(" "),d=D?normalizeSearchText(w[E]):w[E],d=d.replace(/[()[\\\]]/g,".").replace(/[+]/g,"\\+").replace(/[*]/g,"\\*"),s=d.split(" "),c=D?"":"i",u={$regex:RegExp(d,c)},1===f.length)r=f[0],j.path(r)&&((d={})[r]=u,o=d,1<s.length)&&(o={$and:s.map(function(e){var t={};return t[r]={$regex:RegExp(e,c)},t})});else for(n=function(r){var e,t,n,i;j.path(r)?(o.$or||(o.$or=[]),s.length<=1?o.$or.push(((n={})[r]=u,n)):o.$or.push({$and:s.map(function(e){var t={};return t[r]={$regex:RegExp(e,c)},t})})):r.includes(".")&&(t=(n=r.split("."))[0],n=n[1],i=j.path(t))&&i.options.ref&&(a[t]?a[t].$match.$or.push(((e={})[n]=u,e)):a[t]={collection:i.options.ref,$match:{$or:[((e={})[n]=u,e)]}})},i=0,l=f;i<l.length;i++)p=l[i],n(p);return 0===Object.keys(a).length?[3,3]:[4,Promise.all(Object.entries(a).map(function(e){return __awaiter(h,[e],void 0,function(e){var t,r,n=e[0],i=e[1];return __generator(this,function(e){switch(e.label){case 0:return[4,mongoose_1.connection.collection(i.collection).find(__assign(__assign({},i.$match),g)).project({_id:1}).toArray()];case 1:return t=e.sent(),(t=t.map(function(e){return e._id})).length&&(o.$or||(o.$or=[]),o.$or.push(((r={})[n]={$in:t},r))),[2]}})})}))];case 2:e.sent(),e.label=3;case 3:return[4,v()];case 4:return d=e.sent(),(f=d.$or)&&(delete d.$or,Array.isArray(o.$or)?o.$or=o.$or.concat(f):o.$or=f),[2,{match:__assign(__assign({},d),o),usingTextSearch:t}]}})})}()];case 1:if(d=e.sent(),y=d.match,f=d.usingTextSearch,!(a=w)[N]&&A&&(a[N]=A),d=removeKeys(stringToQuery(a[N]),K),h=S(d),m=[],0!==Object.keys(y).length&&m.push({$match:y}),m.push.apply(m,c),s)m.push.apply(m,__spreadArray(__spreadArray([],p(),!1),[{$count:"size"}],!1));else{if(y=function(){if(f)return{$localSort:{score:{$meta:"textScore"},_id:-1}};if(!w[I]){if(!Q)return{};w[I]=Q}for(var e=/(-)?([\w.]+)/g,t={},r={};null!==(i=e.exec(w[I]));){var n=i[1],i=i[2];!!j.path(i)?t[i]=n?-1:1:r[i]=n?-1:1}return{$localSort:0!==Object.keys(t).length?t:void 0,$foreignSort:0!==Object.keys(r).length?r:void 0}}(),$=[],"true"!==(null==(b=w[G])?void 0:b.toString())){var t=d;void 0===t&&(t={});for(var r=0,n=h;r<n.length;r++){var i=n[r];if(i.field.includes(".")||t[i.field])reemplazarSubdoc(t,i.field,1);else for(var o in t)o.startsWith(i.field+".")&&(delete t[o],t[i.field]=1)}b=__assign({},d),f&&(b.score={$meta:"textScore"}),$.push({$project:b})}else O&&$.push({$project:stringToQuery(O,"0")}),f&&$.push({$addFields:{score:{$meta:"textScore"}}});m.push.apply(m,__spreadArray(__spreadArray(__spreadArray(__spreadArray([],y.$localSort?[{$sort:y.$localSort}]:[],!1),p(),!1),[{$skip:(u-1)*l},{$limit:l}],!1),$,!1))}return[2,{pipeline:m,lookupsConfirmados:h}]}var a})})}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongoose-smart-query",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Optimize rest requests",
|
|
5
5
|
"main": "./dist/mongoose-smart-query.js",
|
|
6
6
|
"types": "./dist/mongoose-smart-query.d.ts",
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@eslint/js": "^10.0.1",
|
|
26
26
|
"@types/jest": "^30.0.0",
|
|
27
|
-
"@types/node": "^25.2
|
|
28
|
-
"eslint": "^10.0.
|
|
27
|
+
"@types/node": "^25.3.2",
|
|
28
|
+
"eslint": "^10.0.2",
|
|
29
29
|
"jest": "^30.2.0",
|
|
30
30
|
"mongoose": "^8.23.0",
|
|
31
31
|
"ts-jest": "^29.4.6",
|
|
32
32
|
"typescript": "^5.9.3",
|
|
33
|
-
"typescript-eslint": "^8.
|
|
33
|
+
"typescript-eslint": "^8.56.1",
|
|
34
34
|
"uglify-js": "^3.19.3"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|