Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions lib/helpers/omitUndefined.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

module.exports = function omitUndefined(val) {
if (val == null || typeof val !== 'object') {
return val;
}
if (Array.isArray(val)) {
for (let i = val.length - 1; i >= 0; --i) {
if (val[i] === undefined) {
val.splice(i, 1);
}
}
}
for (const key of Object.keys(val)) {
if (val[key] === void 0) {
delete val[key];
}
}
return val;
};
10 changes: 2 additions & 8 deletions lib/helpers/query/cast$expr.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const CastError = require('../../error/cast');
const StrictModeError = require('../../error/strict');
const castNumber = require('../../cast/number');
const omitUndefined = require('../omitUndefined');

const booleanComparison = new Set(['$and', '$or']);
const comparisonOperator = new Set(['$cmp', '$eq', '$lt', '$lte', '$gt', '$gte']);
Expand Down Expand Up @@ -125,18 +126,11 @@ function _castExpression(val, schema, strictQuery) {
val.$round = $round.map(v => castNumberOperator(v, schema, strictQuery));
}

_omitUndefined(val);
omitUndefined(val);

return val;
}

function _omitUndefined(val) {
const keys = Object.keys(val);
for (let i = 0, len = keys.length; i < len; ++i) {
(val[keys[i]] === void 0) && delete val[keys[i]];
}
}

// { $op: <number> }
function castNumberOperator(val) {
if (!isLiteral(val)) {
Expand Down
22 changes: 22 additions & 0 deletions lib/mongoose.js
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,28 @@ Mongoose.prototype.skipMiddlewareFunction = Kareem.skipWrappedFunction;

Mongoose.prototype.overwriteMiddlewareResult = Kareem.overwriteResult;

/**
* Takes in an object and deletes any keys from the object whose values
* are strictly equal to `undefined`.
* This function is useful for query filters because Mongoose treats
* `TestModel.find({ name: undefined })` as `TestModel.find({ name: null })`.
*
* #### Example:
*
* const filter = { name: 'John', age: undefined, status: 'active' };
* mongoose.omitUndefined(filter); // { name: 'John', status: 'active' }
* filter; // { name: 'John', status: 'active' }
*
* await UserModel.findOne(mongoose.omitUndefined(filter));
*
* @method omitUndefined
* @param {Object} [val] the object to remove undefined keys from
* @returns {Object} the object passed in
* @api public
*/

Mongoose.prototype.omitUndefined = require('./helpers/omitUndefined');

/**
* The exports object is an instance of Mongoose.
*
Expand Down
2 changes: 2 additions & 0 deletions test/types/base.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@ function setAsObject() {

expectError(mongoose.set({ invalid: true }));
}

const x: { name: string } = mongoose.omitUndefined({ name: 'foo' });
2 changes: 2 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ declare module 'mongoose' {
/** Gets mongoose options */
export function get<K extends keyof MongooseOptions>(key: K): MongooseOptions[K];

export function omitUndefined<T extends Record<string, any>>(val: T): T;

/* ! ignore */
export type CompileModelOptions = {
overwriteModels?: boolean,
Expand Down