Query documents (Read)
Querying Documents (Read)
Mongoose provides various methods for querying documents, ranging from simple find
to complex aggregation operations. Query methods return a Query
object, allowing for chaining to further refine query conditions. The query results can be a single document, an array of documents, or a cursor object, depending on the query method used.
Basic Query Methods
The find
method is the most commonly used query method, returning an array of all matching documents. If no query conditions are provided, it returns all documents in the collection.
const User = mongoose.model('User', userSchema);
// Query all users
User.find({}, (err, users) => {
if (err) return console.error(err);
console.log(users);
});
// Query users older than 18
User.find({ age: { $gt: 18 } }, (err, users) => {
if (err) return console.error(err);
console.log(users);
});
The findOne
method returns the first matching document instead of an array. This is useful when only a single document is needed.
// Query the first user with the name "张三"
User.findOne({ name: '张三' }, (err, user) => {
if (err) return console.error(err);
console.log(user);
});
Query Conditions
Mongoose supports all MongoDB query operators, including comparison operators, logical operators, and element operators.
// Comparison operator example
User.find({ age: { $gte: 20, $lte: 30 } }, (err, users) => {
// Query users aged between 20 and 30
});
// Logical operator example
User.find({ $or: [{ age: { $lt: 18 } }, { age: { $gt: 65 } }] }, (err, users) => {
// Query users younger than 18 or older than 65
});
// Regular expression query
User.find({ name: /^张/ }, (err, users) => {
// Query users whose names start with "张"
});
Query Options
Query methods can accept options parameters to control the behavior of the returned results.
// Limit returned fields
User.find({}, 'name age', (err, users) => {
// Only return the name and age fields
});
// Pagination query
User.find({})
.skip(10) // Skip the first 10 records
.limit(5) // Return 5 records
.exec((err, users) => {
// Records 11 to 15
});
// Sorting
User.find({})
.sort({ age: -1 }) // Sort by age in descending order
.exec((err, users) => {
// Sorted results
});
Advanced Query Techniques
Chained Queries
Mongoose queries support chaining, allowing for the gradual construction of complex queries.
User.find({ age: { $gt: 18 } })
.where('name').equals('张三')
.select('name email')
.limit(5)
.sort({ age: -1 })
.exec((err, users) => {
// Complex query results
});
Query Middleware
Middleware functions can be added before or after queries to execute additional logic.
schema.pre('find', function(next) {
console.log('About to execute query');
next();
});
schema.post('find', function(docs, next) {
console.log('Query completed, returned', docs.length, 'documents');
next();
});
Aggregation Queries
For complex statistical and analytical needs, the aggregation framework can be used.
User.aggregate([
{ $match: { age: { $gt: 18 } } },
{ $group: { _id: "$city", total: { $sum: 1 } } },
{ $sort: { total: -1 } }
]).exec((err, result) => {
// Group adult users by city and count them
});
Query Performance Optimization
Index Usage
Proper use of indexes can significantly improve query performance.
// Create an index
userSchema.index({ name: 1, age: -1 });
// Check if a query used an index
User.find({ name: '张三' }).explain((err, explanation) => {
console.log(explanation.executionStats.executionStages.inputStage.indexName);
});
Batch Query Optimization
For queries involving large amounts of data, cursors or batch operations can be used.
// Use a cursor to process large datasets
const cursor = User.find().cursor();
cursor.on('data', (doc) => {
// Process each document
}).on('end', () => {
// Processing complete
});
// Batch query
User.find().batchSize(100).exec((err, users) => {
// Fetch 100 records at a time from the server
});
Query Error Handling
Properly handling query errors is key to ensuring application robustness.
User.find({ invalidField: 'value' })
.then(users => {
// Success handling
})
.catch(err => {
if (err.name === 'CastError') {
console.log('Field type error');
} else if (err.name === 'ValidationError') {
console.log('Validation error');
} else {
console.log('Other error', err);
}
});
Queries and Schema Validation
Queries automatically apply validation rules defined in the schema.
const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
match: /.+\@.+\..+/
}
});
// Queries will validate the email format
User.find({ email: 'invalid-email' }, (err) => {
// Will trigger a validation error
});
Virtual Fields and Queries
Virtual fields are not stored in the database but can be used in query results.
userSchema.virtual('fullName').get(function() {
return this.firstName + ' ' + this.lastName;
});
User.findOne().then(user => {
console.log(user.fullName); // Can access virtual fields
});
Queries and Population
Mongoose's population feature can automatically replace referenced fields in documents.
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); // Directly access the author's name
});
Geospatial Queries
For documents containing geospatial data, special geospatial queries can be used.
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 => {
// Query places within 1000 meters of the given coordinates
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:创建文档(Create)
下一篇:更新文档(Update)