Use $push to insert elements into an array

An element is inserted into an array using the $push command
This blog post will take you through various ways of
pushing to an array. You will learn how to:

  • push from the start of an array
  • push from the end of an array
  • push multiple elements at once
  • push to an array and slice
  • push to an array and sort
  • avoid gotchas

In the most general case, you can push an element to the end of the array (i.e., append) by performing an update with the $push operator. In the example below we use it to append an 'i' to the alphabet array.

Push from the start of the array

To push an element to a position other than the end of the array, use the $position modifier along with the $each modifier.

A non-negative $position value describes the position a value will be pushed to by counting from the start, i.e. the left side of an array. In the above example, the position value is 8. Given this position value, MongoDB pushes the new element 'i' to the 8th position in the 0-indexed array alphabet which is between the 'h' and the 'j' .

Illustration that shows the mappings of non-negative values to positions in arrays. The $position value describes the respective position counted from the start, i.e. the left side of an array. The array shown is [ "a", "b", "c", "d", "e", "f", "g", "h", "j" ]. 0 is shown to indicate the position before the 'a', 1 the position before the 'b', etc.

Push from the end of the array

With MongoDB's 3.6 release, there is additional functionality for inserting into an array: you can now give negative values to the $position modifier. The above update could now also be done like this:

A negative $position value describes the position a value will be pushed to by counting from the end, i.e. the right side of an array. In this code snippet, the $position modifier was assigned the value -1. The negative number indicates to MongoDB to start counting from the right and insert the element before the last element in this case. To insert before the n last elements you would use -n as the position value.

Illustration that shows the mappings of negative values to positions in arrays. The $position value describes the respective position counted from the end, i.e. the right side of an array. The array shown is [ "a", "b", "c", "d", "e", "f", "g", "h", "j" ]. -1 is shown to indicate the position before the last element 'k', -2 the position before the 'h', etc.In scenarios where you know you need to insert an object before the n last elements in an array, the option of specifying the position by counting from the right simplifies writing and reading these operations.

Push multiple elements at once

The modifier $each allows you to push each element from an array of elements to a document's array at a specified position.

Let's break down what happens when you push ['f', 'g', 'h']  by considering each element from the array as its own stage. In this case 'f' would be pushed to the specified position -2 first, then 'g', and, lastly, 'h'. The element ending up in the position -2 after all elements are inserted is therefore 'h'. The preceding elements are in positions -3 and -4. Overall, the elements of the array are inserted in order.

 

Push onto an array while slicing

Now let's look at some more options of modifying an array while pushing. Let's consider an online store that keeps track of the last 3 items a user viewed. When adding a new item, $slice can be used to limit the number of array elements:

By not using the $position modifier, the operation pushes the item 'Dates' to the end of the array. To keep the array to only the 3 most recent items, you then slice the recent-items. The negative value -3 for the $slice modifier results in an array with the last 3 elements remaining in the array.

If instead you need to keep the first n elements of the array, you can specify a positive value n for the $slice modifier. Specifying 0, on the other hand, will result in your result array being an empty array.

If you are backfilling data, for example, you can also specify a $position modifier. Note that the $slice modifier takes effect after the element(s) are pushed. To use $slice to just slice an array without adding new elements you can specify $each: [ ] .

Push onto an array while sorting

Apart from slicing you may also want to use $sort to sort an array or insert into an array while keeping it sorted. You can use it along with $slice and $position. Note that specifying any position is futile, since the sorting will move the element as needed. The order in which $sort, $position, and $slice are applied is: first $position, then $sort, and lastly $slice.

Let's consider a game that stores its top 10 highest scores. We will use slice and sort to add a new high score while keeping the list sorted and limited to 10 scores:

The update query adds the new score 72  and the array is then sorted before it is sliced to the specified 10 elements. In this example, the array is sorted based on the numbers it contains. However, if you have documents within an array you can also sort based on a field within those documents.

Avoid gotchas

$position = -0

You may think that this would add the element to the end of the array but alas -0 is the same as 0 and therefore the element will be pushed to the beginning of the array.

No $position

Removing the $position modifier results in the element being added to the end of the array.

$position = -999999999

If the absolute value of a negative position value is greater or equal to the length of the array, the element being added will be pushed to the beginning of the array.

Performance implications

Be aware that push operations that specify a position rewrite the entire array which can lead to high CPU usage during updates. The rewriting of arrays results in many index key updates for indexes on those arrays, larger oplog entries, and consequently a shorter oplog window.

In general large arrays can be problematic for performance. For very fast moving array contents, consider breaking arrays out into their own collections.

Learn more

To read more about this check out the documentation: docs.mongodb.com/manual/reference/operator/update/push/.

If you're interested in more MongoDB Tips, follow us on Twitter @mlab. Also, if you could use help with an mLab-hosted database, you can always contact support@mlab.com.

 

Naomi Pentrel is a Developer Advocate at mLab and a full-stack pythonista with a focus on improving developer workflows. She has previously worked at companies such as Google, Microsoft, and Bloomberg. When not at work or a organizing Smooth DevOps, Naomi is an avid Pokémon master and a slayer of houseplants.

About Naomi Pentrel

Naomi Pentrel is a Developer Advocate at mLab and a full-stack pythonista with a focus on improving developer workflows. She has previously worked at companies such as Google, Microsoft, and Bloomberg. When not at work or a organizing Smooth DevOps, Naomi is an avid Pokémon master and a slayer of houseplants.

, , , , , , ,