数组处理($unwind、$filter、$slice等)
数组处理($unwind、$filter、$slice等)
MongoDB提供了丰富的数组操作符,用于处理和操作文档中的数组字段。这些操作符可以在聚合管道中使用,也可以在查询和更新操作中使用。数组处理是MongoDB中非常常见的操作,掌握这些操作符能够极大地提高数据处理的灵活性和效率。
$unwind操作符
$unwind
操作符用于将数组字段中的每个元素拆分成单独的文档。这对于需要对数组中的每个元素进行单独处理的场景非常有用。
// 示例数据
db.orders.insertMany([
{ _id: 1, items: ["apple", "banana", "orange"] },
{ _id: 2, items: ["pear", "grape"] }
])
// 使用$unwind展开数组
db.orders.aggregate([
{ $unwind: "$items" }
])
// 结果
[
{ _id: 1, items: "apple" },
{ _id: 1, items: "banana" },
{ _id: 1, items: "orange" },
{ _id: 2, items: "pear" },
{ _id: 2, items: "grape" }
]
$unwind
还支持一些选项参数:
preserveNullAndEmptyArrays
:默认为false,如果设置为true,当数组字段为null、空或不存在时,会保留该文档
db.orders.aggregate([
{ $unwind: { path: "$items", preserveNullAndEmptyArrays: true } }
])
$filter操作符
$filter
操作符用于根据指定的条件过滤数组元素,返回一个新的数组。
// 示例数据
db.products.insertMany([
{ _id: 1, name: "Laptop", prices: [1200, 1100, 1000] },
{ _id: 2, name: "Phone", prices: [800, 750, 700] }
])
// 使用$filter筛选价格大于1000的元素
db.products.aggregate([
{
$project: {
name: 1,
highPrices: {
$filter: {
input: "$prices",
as: "price",
cond: { $gt: ["$$price", 1000] }
}
}
}
}
])
// 结果
[
{ _id: 1, name: "Laptop", highPrices: [1200, 1100] },
{ _id: 2, name: "Phone", highPrices: [] }
]
$slice操作符
$slice
操作符用于返回数组的子集,可以指定开始位置和数量。
// 示例数据
db.blogposts.insertMany([
{ _id: 1, title: "Post 1", comments: ["Great!", "Nice", "Awesome"] },
{ _id: 2, title: "Post 2", comments: ["First", "Second", "Third", "Fourth"] }
])
// 获取前2条评论
db.blogposts.aggregate([
{
$project: {
title: 1,
firstTwoComments: { $slice: ["$comments", 2] }
}
}
])
// 结果
[
{ _id: 1, title: "Post 1", firstTwoComments: ["Great!", "Nice"] },
{ _id: 2, title: "Post 2", firstTwoComments: ["First", "Second"] }
]
// 从第2个元素开始获取2条评论
db.blogposts.aggregate([
{
$project: {
title: 1,
sliceComments: { $slice: ["$comments", 1, 2] }
}
}
])
$map操作符
$map
操作符用于对数组中的每个元素应用表达式,并返回结果数组。
// 示例数据
db.products.insertMany([
{ _id: 1, name: "Laptop", prices: [1200, 1100, 1000] },
{ _id: 2, name: "Phone", prices: [800, 750, 700] }
])
// 对价格数组中的每个元素应用折扣
db.products.aggregate([
{
$project: {
name: 1,
discountedPrices: {
$map: {
input: "$prices",
as: "price",
in: { $multiply: ["$$price", 0.9] } // 10%折扣
}
}
}
}
])
// 结果
[
{ _id: 1, name: "Laptop", discountedPrices: [1080, 990, 900] },
{ _id: 2, name: "Phone", discountedPrices: [720, 675, 630] }
]
$reduce操作符
$reduce
操作符用于将数组元素通过表达式组合成单个值。
// 示例数据
db.sales.insertMany([
{ _id: 1, items: [10, 20, 30] },
{ _id: 2, items: [5, 15, 25] }
])
// 计算数组元素的总和
db.sales.aggregate([
{
$project: {
total: {
$reduce: {
input: "$items",
initialValue: 0,
in: { $add: ["$$value", "$$this"] }
}
}
}
}
])
// 结果
[
{ _id: 1, total: 60 },
{ _id: 2, total: 45 }
]
$size操作符
$size
操作符用于返回数组的长度。
// 示例数据
db.blogposts.insertMany([
{ _id: 1, title: "Post 1", comments: ["Great!", "Nice", "Awesome"] },
{ _id: 2, title: "Post 2", comments: ["First", "Second"] }
])
// 获取评论数量
db.blogposts.aggregate([
{
$project: {
title: 1,
commentCount: { $size: "$comments" }
}
}
])
// 结果
[
{ _id: 1, title: "Post 1", commentCount: 3 },
{ _id: 2, title: "Post 2", commentCount: 2 }
]
$concatArrays操作符
$concatArrays
操作符用于连接多个数组。
// 示例数据
db.students.insertMany([
{ _id: 1, name: "Alice", grades1: [80, 85], grades2: [90, 95] },
{ _id: 2, name: "Bob", grades1: [70, 75], grades2: [60, 65] }
])
// 合并两个成绩数组
db.students.aggregate([
{
$project: {
name: 1,
allGrades: { $concatArrays: ["$grades1", "$grades2"] }
}
}
])
// 结果
[
{ _id: 1, name: "Alice", allGrades: [80, 85, 90, 95] },
{ _id: 2, name: "Bob", allGrades: [70, 75, 60, 65] }
]
$arrayElemAt操作符
$arrayElemAt
操作符用于返回数组中指定位置的元素。
// 示例数据
db.products.insertMany([
{ _id: 1, name: "Laptop", prices: [1200, 1100, 1000] },
{ _id: 2, name: "Phone", prices: [800, 750, 700] }
])
// 获取第二个价格
db.products.aggregate([
{
$project: {
name: 1,
secondPrice: { $arrayElemAt: ["$prices", 1] }
}
}
])
// 结果
[
{ _id: 1, name: "Laptop", secondPrice: 1100 },
{ _id: 2, name: "Phone", secondPrice: 750 }
]
$in操作符
$in
操作符用于判断一个值是否在数组中。
// 示例数据
db.users.insertMany([
{ _id: 1, name: "Alice", roles: ["admin", "editor"] },
{ _id: 2, name: "Bob", roles: ["editor"] },
{ _id: 3, name: "Charlie", roles: ["viewer"] }
])
// 查找具有admin角色的用户
db.users.find({
roles: { $in: ["admin"] }
})
// 结果
[
{ _id: 1, name: "Alice", roles: ["admin", "editor"] }
]
$all操作符
$all
操作符用于判断数组是否包含所有指定的元素。
// 示例数据
db.courses.insertMany([
{ _id: 1, title: "Math", tags: ["algebra", "geometry", "calculus"] },
{ _id: 2, title: "Physics", tags: ["mechanics", "optics"] },
{ _id: 3, title: "Chemistry", tags: ["organic", "inorganic", "physical"] }
])
// 查找同时包含algebra和geometry标签的课程
db.courses.find({
tags: { $all: ["algebra", "geometry"] }
})
// 结果
[
{ _id: 1, title: "Math", tags: ["algebra", "geometry", "calculus"] }
]
数组更新操作符
MongoDB提供了一系列数组更新操作符,用于修改数组字段:
$push操作符
$push
操作符用于向数组添加元素。
// 向数组添加一个元素
db.students.updateOne(
{ _id: 1 },
{ $push: { scores: 85 } }
)
// 向数组添加多个元素
db.students.updateOne(
{ _id: 1 },
{ $push: { scores: { $each: [90, 92] } } }
)
$addToSet操作符
$addToSet
操作符用于向数组添加元素,但只有当元素不存在时才添加。
db.students.updateOne(
{ _id: 1 },
{ $addToSet: { scores: 85 } } // 只有当85不存在时才会添加
)
$pop操作符
$pop
操作符用于从数组移除第一个或最后一个元素。
// 移除最后一个元素
db.students.updateOne(
{ _id: 1 },
{ $pop: { scores: 1 } }
)
// 移除第一个元素
db.students.updateOne(
{ _id: 1 },
{ $pop: { scores: -1 } }
)
$pull操作符
$pull
操作符用于从数组中移除所有匹配指定条件的元素。
db.students.updateOne(
{ _id: 1 },
{ $pull: { scores: { $gte: 90 } } } // 移除所有大于等于90的分数
)
数组查询操作符
MongoDB提供了一些专门用于查询数组的操作符:
$elemMatch操作符
$elemMatch
操作符用于查询数组中至少有一个元素满足所有指定条件的文档。
// 示例数据
db.students.insertMany([
{ _id: 1, name: "Alice", scores: [ { math: 80 }, { math: 90 } ] },
{ _id: 2, name: "Bob", scores: [ { math: 70 }, { math: 85 } ] }
])
// 查找数学成绩有大于85的学生
db.students.find({
scores: { $elemMatch: { math: { $gt: 85 } } }
})
// 结果
[
{ _id: 1, name: "Alice", scores: [ { math: 80 }, { math: 90 } ] }
]
数组索引查询
可以直接使用数组索引进行查询:
// 查找第一个数学成绩大于85的学生
db.students.find({
"scores.0.math": { $gt: 85 }
})
数组聚合操作符
在聚合管道中,还有一些其他有用的数组操作符:
$first和$last操作符
$first
和$last
操作符用于获取数组的第一个或最后一个元素。
db.students.aggregate([
{
$project: {
name: 1,
firstScore: { $first: "$scores" },
lastScore: { $last: "$scores" }
}
}
])
$isArray操作符
$isArray
操作符用于检查一个值是否为数组。
db.students.aggregate([
{
$project: {
name: 1,
isScoresArray: { $isArray: "$scores" }
}
}
])
数组操作符的组合使用
在实际应用中,经常需要组合使用多个数组操作符来实现复杂的数据处理。
// 示例:计算每个学生最高分的平均值
db.students.aggregate([
{
$project: {
name: 1,
maxScore: {
$reduce: {
input: "$scores",
initialValue: 0,
in: { $max: ["$$value", "$$this.math"] }
}
}
}
},
{
$group: {
_id: null,
avgMaxScore: { $avg: "$maxScore" }
}
}
])
性能考虑
在处理大型数组时,需要注意以下性能问题:
- 索引使用:可以为数组字段创建索引,但要注意多键索引的限制
- 数组大小:大型数组会影响查询性能
- 操作复杂度:某些数组操作的时间复杂度较高
// 为数组字段创建索引
db.students.createIndex({ "scores.math": 1 })
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:多表关联($lookup)