In MongoDB, updating array elements involves using a variety of update operators depending on what you want to do — such as adding, removing, or modifying elements. Below is a complete guide with example code snippets for different array update operations using MongoDB (with db.collection.updateOne() and updateMany()).
db.students.updateOne(
{ _id: 1 },
{ $push: { scores: 95 } }
)db.students.updateOne(
{ _id: 1 },
{ $push: { scores: { $each: [88, 76] } } }
)db.students.updateOne(
{ _id: 1 },
{ $push: { scores: { $each: [67, 92], $sort: -1 } } }
)db.students.updateOne(
{ _id: 1 },
{ $pull: { scores: 76 } }
)db.students.updateOne(
{ _id: 1 },
{ $pull: { scores: { $lt: 50 } } }
)db.students.updateOne(
{ _id: 1, "scores": 88 },
{ $set: { "scores.$": 90 } }
)db.students.updateOne(
{ _id: 1 },
{
$set: {
"scores.$[elem]": 100
}
},
{
arrayFilters: [ { "elem": { $lt: 50 } } ]
}
)db.students.updateOne(
{ _id: 1 },
{ $set: { scores: [80, 90, 100] } }
)db.students.updateOne(
{ _id: 1 },
{ $addToSet: { scores: 95 } }
)// Remove last
db.students.updateOne(
{ _id: 1 },
{ $pop: { scores: 1 } }
)
// Remove first
db.students.updateOne(
{ _id: 1 },
{ $pop: { scores: -1 } }
)Requires arrayFilters:
db.students.updateOne(
{ _id: 1 },
{
$inc: { "scores.$[elem]": 5 }
},
{
arrayFilters: [ { "elem": { $eq: 90 } } ]
}
)Let me know your specific use case (e.g., update nested arrays, arrays of objects, etc.), and I can generate tailored code for that as well.
When working with arrays of documents in MongoDB (i.e., an array containing objects rather than simple values), update operations become more complex and powerful. Here's a comprehensive list of all types of updates you can perform on arrays of documents, with code examples using the MongoDB shell or driver syntax.
We’ll use this document as our base example:
{
_id: 1,
name: "Alice",
contacts: [
{ type: "email", value: "alice@example.com" },
{ type: "phone", value: "123456789" }
]
}db.users.updateOne(
{ _id: 1, "contacts.type": "email" },
{ $set: { "contacts.$.value": "newalice@example.com" } }
)db.users.updateOne(
{ _id: 1 },
{
$set: {
"contacts.$[elem].value": "updated-phone",
"contacts.$[elem].verified": true
}
},
{
arrayFilters: [ { "elem.type": "phone" } ]
}
)db.users.updateOne(
{ _id: 1 },
{
$push: {
contacts: { type: "fax", value: "999888777" }
}
}
)db.users.updateOne(
{ _id: 1 },
{
$push: {
contacts: {
$each: [
{ type: "linkedin", value: "alice-linkedin" },
{ type: "twitter", value: "@alice" }
]
}
}
}
)db.users.updateOne(
{ _id: 1 },
{
$addToSet: {
contacts: { type: "email", value: "alice@example.com" }
}
}
)db.users.updateOne(
{ _id: 1 },
{
$pull: {
contacts: { type: "fax", value: "999888777" }
}
}
)db.users.updateOne(
{ _id: 1 },
{
$pull: {
contacts: { type: { $in: ["linkedin", "twitter"] } }
}
}
)Example with deeper nesting:
{
_id: 2,
name: "Bob",
projects: [
{
name: "Alpha",
tasks: [
{ title: "Design", status: "open" },
{ title: "Code", status: "in progress" }
]
}
]
}db.users.updateOne(
{ _id: 2 },
{
$set: {
"projects.$[project].tasks.$[task].status": "done"
}
},
{
arrayFilters: [
{ "project.name": "Alpha" },
{ "task.title": "Design" }
]
}
)db.users.updateOne(
{ _id: 1 },
{
$push: {
contacts: {
$each: [],
$sort: { type: 1 }
}
}
}
)Useful when adding multiple items and keeping array size fixed.
db.users.updateOne(
{ _id: 1 },
{
$push: {
contacts: {
$each: [
{ type: "extra", value: "extra-value" }
],
$slice: -3
}
}
}
)db.users.updateOne(
{ _id: 1 },
{
$inc: {
"contacts.$[elem].priority": 1
}
},
{
arrayFilters: [ { "elem.type": "phone" } ]
}
)| Operator | Purpose |
|---|---|
$set |
Update a specific field |
$push |
Add to array |
$each |
Push multiple items |
$sort |
Sort pushed items |
$slice |
Limit array size |
$addToSet |
Add only if not present |
$pull |
Remove by condition |
$pop |
Remove first/last item |
$inc |
Increment a field |
arrayFilters |
Target specific documents in array |
$ |
Positional operator for first match |
Would you like to see a real-world case (like a todo app or student-course structure) with all these in action?
Great question! Let's break down how $ne and $not are used in array updates in MongoDB, and how to combine them with update operators like $set, $push, $pull, etc.
Used in the query filter to find documents where a field or an array element does not equal a value.
Sample document:
{
_id: 1,
name: "Alice",
contacts: [
{ type: "email", value: "alice@example.com" },
{ type: "phone", value: "123456789" }
]
}db.users.updateOne(
{
_id: 1,
"contacts": { $not: { $elemMatch: { type: "fax" } } }
},
{
$push: {
contacts: { type: "fax", value: "999-888-777" }
}
}
)Here, $not + $elemMatch ensures the array does not already contain a document with type: "fax".
Update the email only if it's not already the desired value:
db.users.updateOne(
{
_id: 1,
"contacts.type": "email",
"contacts.value": { $ne: "updated@example.com" }
},
{
$set: {
"contacts.$.value": "updated@example.com"
}
}
)Used to invert the result of another operator, like $regex, $gt, etc.
db.users.updateOne(
{ _id: 1 },
{
$set: {
"contacts.$[elem].value": "unknown@example.com"
}
},
{
arrayFilters: [
{ "elem.type": "email", "elem.value": { $not: /@example\.com$/ } }
]
}
)This updates the email value only if it does not end with "@example.com".
| Operator | Purpose | Example |
|---|---|---|
$ne |
Match values not equal to something | { "contacts.value": { $ne: "x" } } |
$not |
Negate a condition (like regex, gt, etc.) | { "contacts.value": { $not: /regex/ } } |
$not + $elemMatch |
Avoid pushing duplicate object to array | { contacts: { $not: { $elemMatch: { type: "x" } } } } |
db.users.updateOne(
{
_id: 1,
contacts: {
$not: {
$elemMatch: {
type: "linkedin",
value: "linkedin.com/alice"
}
}
}
},
{
$push: {
contacts: { type: "linkedin", value: "linkedin.com/alice" }
}
}
)This prevents duplicate documents inside the contacts array.
Let me know if you’d like examples using $addToSet, $pull, or $inc with $ne or $not!
Great follow-up! Here's a clear breakdown:
-
On their own,
$neand$notin the query filter only help find documents. -
The actual update behavior (first element vs all elements) depends on:
- Whether you're using the positional
$operator – updates only the first matching element. - Or
$[<identifier>]witharrayFilters– lets you target multiple/matching elements in the array.
- Whether you're using the positional
db.users.updateOne(
{
_id: 1,
"contacts.value": { $ne: "updated@example.com" }
},
{
$set: {
"contacts.$.value": "updated@example.com"
}
}
)🔸 This will update only the first element in contacts where value != "updated@example.com".
db.users.updateOne(
{ _id: 1 },
{
$set: {
"contacts.$[elem].value": "updated@example.com"
}
},
{
arrayFilters: [
{ "elem.type": "email", "elem.value": { $ne: "updated@example.com" } }
]
}
)🔸 This will update all email contacts in the array that do not already have the desired value.
For example:
{
contacts: { $not: { $elemMatch: { type: "fax" } } }
}→ This controls whether the document should be updated at all, based on the contents of the array.
It does not decide which array elements get updated — that's controlled by the update expression, not the filter.
| Feature | Behavior |
|---|---|
$ (positional operator) |
Updates first matching array element |
$[<identifier>] + arrayFilters |
Updates all matching elements based on filter |
$ne or $not in query |
Just filter which documents get updated, not which array elements |
$not in arrayFilters |
Lets you negate array field conditions for multi-element updates |
Would you like to try a real-time before-and-after example to see how these updates affect array contents?