阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 数组处理($unwind、$filter、$slice等)

数组处理($unwind、$filter、$slice等)

作者:陈川 阅读数:5973人阅读 分类: MongoDB

数组处理($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" }
    }
  }
])

性能考虑

在处理大型数组时,需要注意以下性能问题:

  1. 索引使用:可以为数组字段创建索引,但要注意多键索引的限制
  2. 数组大小:大型数组会影响查询性能
  3. 操作复杂度:某些数组操作的时间复杂度较高
// 为数组字段创建索引
db.students.createIndex({ "scores.math": 1 })

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌