Skip to content

dimadeveatii/mongo-dot-notation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

67 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mongo-dot-notation

Transform objects to MongoDB update instructions.

Build status Coverage Status NPM Version Downloads

import { flatten, $timestamp, $unset } from 'mongo-dot-notation';

const user = flatten({
  firstName: 'Alice',
  contact: { phone: '874-478-1254' },
  address: {
    primary: {
      state: 'NY',
      nr: 42,
    },
  },
});

Sets user to:

{
  "$set": {
    "firstName": "Alice",
    "contact.phone": "874-478-1254",
    "address.primary.state": "NY",
    "address.primary.nr": 42
  }
}

Installation

npm install mongo-dot-notation

Highlights

  • Supports all MongoDB update operators
    • Field update operators
    • Array update operators
    • Bitwise update operators
  • No npm dependency on mongo
  • Written in TypeScript
    • Type definitions for all exported functions
  • Supports flattening and updating array elements by index

Usage and examples

Using operators to update fields

import { flatten, $inc, $currentDate, $push, $setOnInsert } from 'mongo-dot-notation';

const review = {
  // Add a comment and keep only the last ten ones
  comments: $push('Like it!').$each().$slice(-10),
  rating: 10,
  counters: {
    // increment the `total` by one
    total: $inc(),
  },
  details: {
    // set only if the document is inserted
    createdOn: $setOnInsert(new Date()),
    // set to current date as a mongo Date
    updatedOn: $currentDate(),
  },
};

// Provided reviews is a MongoDB collection
await reviews.updateOne(reviewId, flatten(review), { upsert: true });

Flattening arrays

import { flatten } from 'mongo-dot-notation';

const user = {
  phones: [
    {
      number: '123-456-789',
      primary: true,
    },
    {
      number: '789-012-345',
    },
  ],
};

// Provided users is a MongoDB collection
await users.updateOne(userId, flatten(user, { array: true }));

The above user object is flattened to:

{
  "phones.0.number": "123-456-789",
  "phones.0.primary": true,
  "phones.1.number": "789-012-345"
}

Using positional operator

import { flatten, $, $inc } from 'mongo-dot-notation';

const student = {
  grades: $().$inc(),
};

// Finds the element with value 80 in the "grades" array
// and increments it by one.
student.updateOne(
  { _id: 1, grades: 80 },
  flatten(student) // { $inc: { "grades.$" : 1 } }
);

The position operator supports updating a nested document:

import { flatten, $, $inc } from 'mongo-dot-notation';

const student = {
  grades: $('value').$inc(),
};

// Finds the document with "value" field equal to 80 in the "grades" array
// and increments it by one.
student.updateOne(
  { _id: 1, grades: 80 },
  flatten(student) // { $inc: { "grades.$.value" : 1 } }
);

To update all elements in a array, use all positional operator:

import { flatten, $, $inc } from 'mongo-dot-notation';

const student = {
  grades: $('[]').$inc(),
};

// Increment all grades by one
student.updateOne(
  { _id: 1 },
  flatten(student) // { $inc: { "grades.$[]" : 1 } }
);

Similarly, updating nested documents:

import { flatten, $, $inc } from 'mongo-dot-notation';

const student = {
  grades: $('[].values').$inc(),
};

// Increment all grades' values by one
student.updateOne(
  { _id: 1 },
  flatten(student) // { $inc: { "grades.$[].values" : 1 } }
);

Using filtered positional operator

import { flatten, $, $mul } from 'mongo-dot-notation';

const student = {
  grades: $('[element]').$mul(9),
};

// Multiply by ten all grades that are below 9
student.updateOne(
  { _id: 1 },
  flatten(student), // { $mul: { "grades.$[element]" : 10 } }
  { arrayFilters: [{ element: { $lte: 9 } }] }
);

Similarly, updating nested documents:

import { flatten, $, $mul } from 'mongo-dot-notation';

const student = {
  grades: $('[element].value').$mul(9),
};

// Multiply by ten all grades that are below 9
student.updateOne(
  { _id: 1 },
  flatten(student), // { $mul: { "grades.$[element].value" : 10 } }
  { arrayFilters: [{ 'element.value': { $lte: 9 } }] }
);

Merge array documents

Using positional operator to merge fields into the matched element:

import { flatten, $, $inc, $currentDate } from 'mongo-dot-notation';

const student = {
  grades: $().merge({
    class: '101',
    prof: 'Alice',
    value: $inc(),
    date: $currentDate(),
  }),
};

flatten(student);

Result:

{
  "$set": {
    "grades.$.class": "101",
    "grades.$.prof": "Alice"
  },
  "$inc": {
    "grades.$.value": 1
  },
  "$currentDate": {
    "grades.$.date": { "$type": "date" }
  }
}

To update all elements, use $('[]') instead of $() in the above example.

Update nested arrays

Using positional operator to update nested arrays:

import { flatten, $, $mul } from 'mongo-dot-notation';

const student = {
  grades: $().merge({
    questions: $('[]').merge({
      value: $mul(100),
    }),
  }),
};

flatten(student);

Calling flatten(student) results in:

{
  "$mul": {
    "grades.$.questions.$[].value": 100
  }
}

See the end-to-end tests file for more examples.

API

Table of contents

Options

The following options are available:

Option Description
array (default false) if true, arrays will be flattened and their indexes will be used as keys.
skipEmptyObjects (default false) if true, empty objects are ignored and removed from the flattened result.

Example:

flatten({ rules: [{ value: 7 }] }, { array: true });
// { $set: { 'rules.0.value': 7 } }

flatten({ rules: [{ value: 7 }] }, { array: false });
// { $set: { 'rules': [{value: 7}] } }

flatten({ left: { x: 1 }, right: {} }, { skipEmptyObjects: true });
// { $set: { 'left.x': 1 } }

flatten({ left: { x: 1 }, right: {} }, { skipEmptyObjects: false });
// { $set: { 'left.x': 1, 'right': {} } }

flatten

$flatten<T>(obj: T, options?: Options)

Transforms a given object into the MongoDB's update instructions.

Param Description
obj (required) the input object to transform
options (optional) additional options, see Options

Example:

flatten({
  firstName: 'Alice',
  contact: { phone: '874-478-1254' },
  address: {
    primary: {
      state: 'NY',
      nr: 42,
    },
  },
});

isOperator

isOperator<T>(obj: T): boolean

Checks if a given object is an operator.

Param Description
obj (required) the input object to check

Example:

isOperator($set(1)); // true
isOperator({}); // false

Field update operators

$currentDate

$currentDate(type?: 'date' | 'timestamp')

Param Description
type (default date) sets to MongoDB's Date or Timestamp type.

Sets the value of a field to the current date.

Example:

flatten({
  createdOn: $currentDate(),
});

MongoDB manual

$timestamp

$timestamp()

Sets the value of a field to the current date as a MondoDB's Timestamp type.

This function is an alias for $currentDate('timestamp').

Example:

flatten({
  updatedOn: $timestamp(),
});

MongoDB manual

$inc

$inc<T>(value?: T)

Increments a field by a specified value.

Param Description
value (default 1) increment value

Example:

flatten({
  visits: $inc(),
  clicks: $inc(5),
});

MongoDB manual

$min

$min<T>(value: T)

Updates the value of the field to a specified value if the specified value is less than the current value of the field.

Param Description
value (required) min value

Example:

flatten({
  score: $min(100),
});

MongoDB manual

$max

$max<T>(value: T)

Updates the value of the field to a specified value if the specified value is greater than the current value of the field.

Param Description
value (required) max value

Example:

flatten({
  score: $max(0),
});

MongoDB manual

$mul

$mul<T>(value?: T)

Multiplies the value of a field by a number.

Param Description
value (default 1) multiply factor

Example:

flatten({
  score: $mul(2.5),
});

MongoDB manual

$rename

$rename(field: string)

Updates the name of a field.

Param Description
field (required) new field name

Example:

flatten({
  profile: {
    first_name: $rename('firstName'),
  },
});

MongoDB manual

$set

$set<T>(value: T)

Replaces the value of a field with the specified value.
This is an implicit operator, but could be useful when an entire object should be replaced.

Param Description
value (required) replacement value

Example:

// Replaces the address object entirely rather than just
// updating the "city" field.
flatten({
  address: $set({ city: 'NY' }),
  profile: { name: 'Alice' },
});

// Outputs:
// {
//   "$set": {
//     "address": { "city": "NY" },
//     "profile.name": "Alice"
//   }
// }

MongoDB manual

$setOnInsert

$setOnInsert<T>(value: T)

Assigns the specified value to the field when { upsert: true } operation is used and results in a new document being created. If the update operation does not result in an insert, does nothing.

Param Description
value (required) the value to set on document creation

Example:

flatten({
  logging: {
    createdOn: $setOnInsert(new Date()),
  },
});

MongoDB manual

$unset

$unset()

Deletes the specified field from a document.

Example:

flatten({
  resetPassword: $unset(),
});

MongoDB manual


Array update operators

$ (positional)

$(field?: number | string)

The positional operator identifies an element or multiple elements matching a given query condition to be updated in an array.

Param Description
field (optional) when empty - performs the update on array's element;
when a number or a string starting with a number, specifies the index of the element to update or its field;
when starts with "[]" or "[query]", specifies that this is an all positional operator;

Example:

// Sets to 7 first element that matches the update query
$().$set(7);

// Increment by one the first element's `score` field that matches the update query
$('score').$inc(1);

// Multiplies all elements by two
$('[]').$mul(2);

// Ensures all elements in array are positive
$('[].score').$max(0);

// Find all `grades` documents that have the `std` lower than seven
// and increment their `grade` by ten.
collection.updateOne(criteria, flatten({ grades: $('[element].grade').$inc(10) }), {
  arrayFilters: [{ 'element.std': { $lt: 7 } }],
});

See update nested arrays for examples using $().merge.

MongoDB manual

$addToSet

$addToSet<T>(value: T | T[])

Adds a value to an array unless the value is already present. To add multiple values, chain with $each operator.

Param Description
value (required) the value to add to the set

Note that while $addToSet([1, 2]) adds the entire array as single element, $addToSet([1, 2]).$each() adds 1 and 2 as separate elements.

Example:

// add just one element
flatten({ permissions: $addToSet('admin') });

// add multiple elements
flatten({ permissions: $addToSet(['read', 'write']).$each() });

MongoDB manual

$pop

$pop(value?: -1 | 1)

Removes the first or last element of an array

Param Description
value (default 1) specify -1 to remove the first element, 1 to remove the last element

Example:

// remove the first element from the array
flatten({ grades: $pop(-1) });
// equivalent to:
flatten({ grades: $pop().first() });

// remove the last element from the array
flatten({ scores: $pop(1) });
// equivalent to:
flatten({ scores: $pop().last() });

MongoDB manual

$pull

$pull<T>(value: T | T[])

Removes from an existing array all instances of a value or values that match a specified condition. Unlike the $pullAll operator, this operator can be used to remove all instances that match a query.

Param Description
value (required) the value(s) to remove or the condition to match for removed elements

Example:

// remove all instances of the value `0` and `1` from the array;
// same as using $pullAll
flatten({ scores: $pull([0, 1]) });

// remove all instances lower than or equal to `3`
flatten({ scores: $pull({ $lte: 3 }) });

// remove all documents with the field `name` equal to `Test`
flatten({ users: $pull({ name: { $eq: 'Test' } }) });

MongoDB manual

$push

$push<T>(value?: T | T[])

Appends a specified value to an array. Can be chained with .$slice(), .$sort() and .$position() modifiers to specify how the array should be updated.
The order in which additional operators are chained doesn't matter, so that $push().$each().$slice().$sort() is the same as $push().$each().$sort().$slice().

Param Description
value (optional) the value(s) to append to the array

Example:

// append one element
flatten({ scores: $push(1) });

// append multiple elements
flatten({ scores: $push([1, 2, 3]).$each() });

// append an element and update to leave only the last ten
flatten({ scores: $push(7).$each().$slice(-10) });

// append an element and update to leave only the last ten sorted by value
flatten({ scores: $push(7).$each().$sort(1).$slice(-10) });

// append an element at position three in the array
flatten({ scores: $push(7).$each().$position(2) });

MongoDB manual

$pullAll

$pullAll<T>(value: T | T[])

Removes all instances of the specified values from an existing array.

Param Description
value (required) the value(s) to remove from the array

Example:

// remove all instances of the value `1` and `2` from the array
flatten({ score: $pullAll([1, 2]) });

// remove all instances of the value `0`
flatten({ score: $pullAll(0) });

MongoDB manual

$slice

$slice(count: number)

Limits the number of array elements. Alias for $push().$each().$slice().

Param Description
count (required) number of elements to take

Example:

// leave only the first 3 elements
flatten({ grades: $slice(3) });

// leave only the last element
flatten({ grades: $slice(-1) });

// empty the array
flatten({ grades: $slice(0) });

MongoDB manual

$sort

$sort<T>(specification?: T)

Orders the elements of an array. Alias for $push().$each().$sort().

Param Description
specification (default 1) sort specification

Example:

// sort ascending
flatten({ scores: $sort(1) });

// sort descending
flatten({ scores: $sort(-1) });

// sort ascending an array of documents with `name` field
flatten({ users: $sort({ name: 1 }) });

MongoDB manual


Bitwise update operators

$bit

$bit()

Performs a bitwise update of a field. Should be chained with a logical operator.

Example:

flatten({
  admin: $bit().$and(7),
  read: $bit().$or(4),
  write: $bit().$xor(3),
});

MongoDB manual

$and

$and<T>(value: T)

Uses a bitwise and operation to update a field. Alias for $bit().$and().

Example:

flatten({
  admin: $and(7),
});

MongoDB manual

$or

$or<T>(value: T)

Uses a bitwise or operation to update a field. Alias for $bit().$or().

Example:

flatten({
  read: $or(4),
});

MongoDB manual

$xor

$xor<T>(value: T)

Uses a bitwise xor operation to update a field. Alias for $bit().$xor().

Example:

flatten({
  write: $xor(3),
});

MongoDB manual

License

MIT