阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 查询文档(Read)

查询文档(Read)

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

查询文档(Read)

Mongoose提供了多种方法来查询文档,从简单的find到复杂的聚合操作。查询方法返回一个Query对象,允许链式调用进一步细化查询条件。查询结果可以是单个文档、文档数组或游标对象,具体取决于使用的查询方法。

基本查询方法

find方法是最常用的查询方法,它返回一个包含所有匹配文档的数组。如果没有提供查询条件,则返回集合中的所有文档。

const User = mongoose.model('User', userSchema);

// 查询所有用户
User.find({}, (err, users) => {
  if (err) return console.error(err);
  console.log(users);
});

// 查询年龄大于18的用户
User.find({ age: { $gt: 18 } }, (err, users) => {
  if (err) return console.error(err);
  console.log(users);
});

findOne方法返回第一个匹配的文档,而不是数组。这在只需要单个文档时很有用。

// 查询名字为"张三"的第一个用户
User.findOne({ name: '张三' }, (err, user) => {
  if (err) return console.error(err);
  console.log(user);
});

查询条件

Mongoose支持MongoDB的所有查询操作符,包括比较操作符、逻辑操作符和元素操作符等。

// 比较操作符示例
User.find({ age: { $gte: 20, $lte: 30 } }, (err, users) => {
  // 查询年龄在20到30之间的用户
});

// 逻辑操作符示例
User.find({ $or: [{ age: { $lt: 18 } }, { age: { $gt: 65 } }] }, (err, users) => {
  // 查询年龄小于18或大于65的用户
});

// 正则表达式查询
User.find({ name: /^张/ }, (err, users) => {
  // 查询名字以"张"开头的用户
});

查询选项

查询方法可以接受选项参数,用于控制返回结果的行为。

// 限制返回字段
User.find({}, 'name age', (err, users) => {
  // 只返回name和age字段
});

// 分页查询
User.find({})
  .skip(10)  // 跳过前10条
  .limit(5)  // 返回5条
  .exec((err, users) => {
    // 第11到15条记录
  });

// 排序
User.find({})
  .sort({ age: -1 })  // 按年龄降序
  .exec((err, users) => {
    // 排序后的结果
  });

高级查询技巧

链式查询

Mongoose查询支持链式调用,可以逐步构建复杂的查询。

User.find({ age: { $gt: 18 } })
  .where('name').equals('张三')
  .select('name email')
  .limit(5)
  .sort({ age: -1 })
  .exec((err, users) => {
    // 复杂的查询结果
  });

查询中间件

可以在查询前后添加中间件函数,执行额外的逻辑。

schema.pre('find', function(next) {
  console.log('即将执行查询');
  next();
});

schema.post('find', function(docs, next) {
  console.log('查询完成,返回了', docs.length, '个文档');
  next();
});

聚合查询

对于复杂的统计和分析需求,可以使用聚合框架。

User.aggregate([
  { $match: { age: { $gt: 18 } } },
  { $group: { _id: "$city", total: { $sum: 1 } } },
  { $sort: { total: -1 } }
]).exec((err, result) => {
  // 按城市分组统计成年用户数量
});

查询性能优化

索引使用

合理使用索引可以显著提高查询性能。

// 创建索引
userSchema.index({ name: 1, age: -1 });

// 查看查询是否使用了索引
User.find({ name: '张三' }).explain((err, explanation) => {
  console.log(explanation.executionStats.executionStages.inputStage.indexName);
});

批量查询优化

对于大量数据的查询,可以使用游标或批量操作。

// 使用游标处理大量数据
const cursor = User.find().cursor();
cursor.on('data', (doc) => {
  // 处理每个文档
}).on('end', () => {
  // 处理完成
});

// 批量查询
User.find().batchSize(100).exec((err, users) => {
  // 每次从服务器获取100条记录
});

查询错误处理

正确处理查询错误是保证应用健壮性的关键。

User.find({ invalidField: 'value' })
  .then(users => {
    // 成功处理
  })
  .catch(err => {
    if (err.name === 'CastError') {
      console.log('字段类型错误');
    } else if (err.name === 'ValidationError') {
      console.log('验证错误');
    } else {
      console.log('其他错误', err);
    }
  });

查询与模式验证

查询时会自动应用模式中定义的验证规则。

const userSchema = new mongoose.Schema({
  email: {
    type: String,
    required: true,
    match: /.+\@.+\..+/
  }
});

// 查询时会验证email格式
User.find({ email: 'invalid-email' }, (err) => {
  // 会触发验证错误
});

虚拟字段与查询

虚拟字段不会存储在数据库中,但可以在查询结果中使用。

userSchema.virtual('fullName').get(function() {
  return this.firstName + ' ' + this.lastName;
});

User.findOne().then(user => {
  console.log(user.fullName);  // 可以访问虚拟字段
});

查询与填充(Population)

Mongoose的填充功能可以自动替换文档中的引用字段。

const storySchema = new mongoose.Schema({
  author: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
});

const Story = mongoose.model('Story', storySchema);

Story.findOne().populate('author').exec((err, story) => {
  console.log(story.author.name);  // 直接访问作者名字
});

地理空间查询

对于包含地理空间数据的文档,可以使用特殊的地理空间查询。

const placeSchema = new mongoose.Schema({
  location: {
    type: { type: String, default: 'Point' },
    coordinates: { type: [Number] }
  }
});
placeSchema.index({ location: '2dsphere' });

Place.find({
  location: {
    $near: {
      $geometry: { type: "Point", coordinates: [ -73.9667, 40.78 ] },
      $maxDistance: 1000
    }
  }
}).then(places => {
  // 查询距离给定坐标1000米内的地点
});

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

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

前端川

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