0Pricing
MongoDB Academy · 课时

更新数组:$push、$pull、$pop、$addToSet

您将使用完整的数组更新运算符集合,以原子方式修改文档中的数组。

更新数组:$push、$pull、$pop、$addToSet 是 CoddyKit 上的免费 MongoDB Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 MongoDB Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 MongoDB Academy 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Array Update Operators Overview

MongoDB provides a rich set of array update operators that let you modify arrays inside documents atomically—without reading the document first, modifying it in application code, and writing it back. These operators are far more efficient and safe in concurrent environments than read-modify-write patterns. The main operators are: $push, $pull, $pop, and $addToSet.

Adding Elements With $push

$push appends one or more values to the end of an array. If the field does not exist, $push creates it as a new array containing the pushed value. $push allows duplicates—if you push the same value twice, it appears twice in the array. Use it when order and duplicates are acceptable, like append-only log arrays.

// Append a single tag
db.articles.updateOne(
  { _id: articleId },
  { $push: { tags: 'mongodb' } }
);

// Push creates the array if it doesn't exist
db.articles.updateOne(
  { _id: newId },
  { $push: { views: { date: new Date(), userId: 'u1' } } }
);
// If 'views' didn't exist, it's now [{ date: ..., userId: 'u1' }]

$push With $each: Pushing Multiple Values

To push multiple values at once without multiple updateOne calls, combine $push with the $each modifier. This is more efficient and atomic. You can also combine $each with $position to insert at a specific index, $slice to cap the array length, or $sort to keep the array sorted after the push.

// Push multiple values atomically
db.articles.updateOne(
  { _id: articleId },
  { $push: { tags: { $each: ['nosql', 'database', 'tutorial'] } } }
);

// Push and keep only the 5 most recent (slice)
db.users.updateOne(
  { _id: userId },
  { $push: { recentViews: { $each: [newView], $slice: -5 } } }  // keep last 5
);

// Push and sort by score descending
db.leaderboard.updateOne(
  { _id: gameId },
  { $push: { scores: { $each: [newEntry], $sort: { score: -1 } } } }
);

Preventing Duplicates With $addToSet

$addToSet adds a value to an array only if it does not already exist. If the value is already in the array, the operation has no effect. This is the correct operator for maintaining a set of unique values, like a list of user tags, role names, or liked post IDs. Unlike $push, $addToSet guarantees no duplicates.

// Add tag only if not already present
db.articles.updateOne(
  { _id: articleId },
  { $addToSet: { tags: 'mongodb' } }
);
// If 'mongodb' is already in tags, nothing changes

// Add multiple unique values with $each
db.users.updateOne(
  { _id: userId },
  { $addToSet: { roles: { $each: ['editor', 'viewer'] } } }
);
// Only adds values not already in roles array

Removing Elements With $pull

$pull removes all array elements that match a specified condition. Unlike $pop (which removes by position), $pull removes by value or condition. You can pull by exact value, by a query expression, or by a complex condition using $elemMatch-style sub-document matching.

// Remove all elements equal to 'draft' from tags
db.articles.updateOne(
  { _id: articleId },
  { $pull: { tags: 'draft' } }
);

// Remove all scores below 50
db.results.updateOne(
  { _id: studentId },
  { $pull: { scores: { $lt: 50 } } }
);

// Pull a specific sub-document from an array
db.users.updateOne(
  { _id: userId },
  { $pull: { addresses: { type: 'work' } } }  // remove all work addresses
);

Removing Multiple Matching Elements

$pull removes all matching elements, not just the first one. If your array has duplicates and you want to remove all copies, $pull handles this in one operation. For removing from multiple documents, combine with updateMany() to pull from every matching document in the collection.

// Remove the role 'temp' from ALL users at once
db.users.updateMany(
  {},
  { $pull: { roles: 'temp' } }
);

// Pull sub-documents matching a condition
db.posts.updateMany(
  {},
  { $pull: { comments: { isSpam: true } } }  // remove spam from all posts
);

Removing From Position With $pop

$pop removes the first or last element of an array based on position. Pass 1 to remove the last element (like a stack pop) or -1 to remove the first element (like a queue dequeue). This is useful for maintaining fixed-size sliding windows or queue-like arrays without reading the array first.

// Remove the LAST element (stack behavior)
db.notifications.updateOne(
  { _id: userId },
  { $pop: { history: 1 } }
);

// Remove the FIRST element (queue behavior)
db.jobs.updateOne(
  { _id: workerId },
  { $pop: { queue: -1 } }
);

// Practical: sliding window of last 10 events
// After push: use $pop: { events: 1 } if length > 10

The $pullAll Operator

$pullAll is a convenience operator that removes all instances of each specified value from an array. It's equivalent to using $pull with $in, but with a slightly simpler syntax when you have a fixed list of values to remove. Note: $pullAll matches exact values and cannot accept query operators.

// Remove multiple specific tags
db.articles.updateOne(
  { _id: articleId },
  { $pullAll: { tags: ['draft', 'wip', 'temp'] } }
);

// Equivalent to:
db.articles.updateOne(
  { _id: articleId },
  { $pull: { tags: { $in: ['draft', 'wip', 'temp'] } } }
);

Combining Array Operators in One Update

You can combine multiple update operators in a single updateOne call, but you cannot apply two operators to the same field in one update. You can, for example, simultaneously $push to a tags array and $inc a count field in one atomic operation, reducing round-trips to the database.

// Push tag AND increment tagCount in one atomic update
db.articles.updateOne(
  { _id: articleId },
  {
    $push: { tags: 'mongodb' },
    $inc: { tagCount: 1 },
    $set: { updatedAt: new Date() }
  }
);
// All three modifications are applied atomically

$push vs $addToSet: Choosing the Right One

The key question when choosing between $push and $addToSet is: do you want to allow duplicates? Use $push when order matters, duplicates are valid, or you're modelling a log/history. Use $addToSet when the array represents a set of unique values like tags, roles, liked IDs, or subscriptions. $addToSet is slightly more expensive because MongoDB checks for existence before inserting.

// $push: suitable for ordered logs (duplicates OK)
db.sessions.updateOne(
  { _id: sessionId },
  { $push: { events: { type: 'click', ts: new Date() } } }
);

// $addToSet: suitable for unique sets
db.users.updateOne(
  { _id: userId },
  { $addToSet: { likedPostIds: postId } }  // no duplicate likes
);

Performance Considerations for Array Updates

Arrays that grow without bound cause document bloat and can exceed MongoDB's 16 MB document size limit. Common mitigation strategies include: using $push with $slice to cap the array at a maximum length; periodically running cleanup operations to remove old elements; or using the Bucket Pattern to group entries into time-bounded bucket documents instead of a single unbounded array.

// Cap array at last 100 notifications
db.users.updateOne(
  { _id: userId },
  {
    $push: {
      notifications: {
        $each: [newNotification],
        $slice: -100,  // keep only last 100 elements
        $sort: { ts: 1 }  // sort by timestamp first
      }
    }
  }
);

Quick Check

Test your understanding of array update operators in MongoDB.

Lesson Recap

In this lesson you learned: $push appends elements (with $each, $slice, $sort modifiers), $addToSet adds only unique values, $pull removes all matching elements, and $pop removes the first or last element by position. Next up we explore positional and filtered positional updates for modifying array elements in place.

常见问题解答

「更新数组:$push、$pull、$pop、$addToSet」课时是免费的吗?

是的 — 「更新数组:$push、$pull、$pop、$addToSet」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 MongoDB Academy 课程的其余内容,请升级到 CoddyKit PRO。 MongoDB Academy 课程共包含 4 节课。

「更新数组:$push、$pull、$pop、$addToSet」这节课中我会学到什么?

您将使用完整的数组更新运算符集合,以原子方式修改文档中的数组。 你通过在浏览器中直接运行的动手代码来练习 MongoDB Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 MongoDB Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 MongoDB Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「更新数组:$push、$pull、$pop、$addToSet」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 MongoDB Academy 课中编写并运行代码吗?

能。每节 MongoDB Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 查询数组:$all、$size 和元素匹配
  2. $elemMatch:匹配数组中的子文档
  3. 更新数组:$push、$pull、$pop、$addToSet
  4. 位置更新和筛选位置更新
← 返回 MongoDB Academy