# mongoose

***

**1. Defining a Schema**

```javascript
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  name: String,
  age: Number
});
```

**2. Creating a Model**

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

**3. Inserting a Document**

```javascript
const user = new User({
  name: 'John',
  age: 30
});

user.save((err) => {
  if (err) return console.error(err);
  console.log('User inserted successfully!');
});
```

**4. Finding a Document by Id**

```javascript
User.findById('5f1234567890abcdef123456', (err, user) => {
  if (err) return console.error(err);
  console.log(user);
});
```

**5. Finding all Documents**

```javascript
User.find((err, users) => {
  if (err) return console.error(err);
  console.log(users);
});
```

**6. Updating a Document**

```javascript
User.findByIdAndUpdate('5f1234567890abcdef123456', { name: 'Jane' }, (err, user) => {
  if (err) return console.error(err);
  console.log(user);
});
```

**7. Deleting a Document**

```javascript
User.findByIdAndDelete('5f1234567890abcdef123456', (err) => {
  if (err) return console.error(err);
  console.log('User deleted successfully!');
});
```

**8. Pagination**

```javascript
User.find()
  .skip(10)
  .limit(5)
  .exec((err, users) => {
    if (err) return console.error(err);
    console.log(users);
  });
```

**9. Sorting**

```javascript
User.find()
  .sort({ name: -1 }) // Sort by name in descending order
  .exec((err, users) => {
    if (err) return console.error(err);
    console.log(users);
  });
```

**10. Filtering by Field**

```javascript
User.find({ age: { $gte: 18 } }) // Find all users with age greater than or equal to 18
  .exec((err, users) => {
    if (err) return console.error(err);
    console.log(users);
  });
```

**11. Populating a Field**

```javascript
User.findById('5f1234567890abcdef123456')
  .populate('friends') // Populate 'friends' field with actual user objects
  .exec((err, user) => {
    if (err) return console.error(err);
    console.log(user);
  });
```

**12. Using Middleware**

```javascript
userSchema.pre('save', async function(next) {
  if (this.name === 'John') {
    next(new Error('Invalid name'));
  }
  next();
});
```

**13. Using Plugins**

```javascript
const timestamps = require('mongoose-timestamps');
userSchema.plugin(timestamps); // Automatically add createdAt and updatedAt fields
```

**14. Creating a Virtual Field**

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

**15. Using Indexes**

```javascript
userSchema.index({ name: 1 }); // Create an index on the 'name' field
```

**16. Upserting a Document**

```javascript
User.findOneAndUpdate({ name: 'John' }, { age: 30 }, { upsert: true }, (err, user) => {
  if (err) return console.error(err);
  console.log(user);
});
```

**17. Using Transactions**

```javascript
const session = await mongoose.startSession();

try {
  await session.withTransaction(async () => {
    const user1 = await User.findByIdAndUpdate('5f1234567890abcdef123456', { age: 31 }, { session });
    const user2 = await User.findByIdAndUpdate('5f1234567890abcdef123457', { age: 32 }, { session });
  });

  await session.commitTransaction();
} catch (err) {
  await session.abortTransaction();
}
```

**18. Using Aggregations**

```javascript
User.aggregate([
  { $match: { age: { $gte: 18 } } }, // Filter by age
  { $group: { _id: '$gender', count: { $sum: 1 } } } // Group by gender and count
])
  .exec((err, results) => {
    if (err) return console.error(err);
    console.log(results);
  });
```

**19. Using Text Search**

```javascript
User.find({ $text: { $search: 'John Doe' } })
  .exec((err, users) => {
    if (err) return console.error(err);
    console.log(users);
  });
```

**20. Using MongoDB Operators**

```javascript
User.find({
  $or: [
    { age: { $lt: 18 } }, // Find users with age less than 18
    { name: { $exists: false } } // Find users without a 'name' field
  ]
})
  .exec((err, users) => {
    if (err) return console.error(err);
    console.log(users);
  });
```

**21. Using Schemas for Nested Objects**

```javascript
const addressSchema = new mongoose.Schema({
  street: String,
  city: String,
  state: String
});

const userSchema = new mongoose.Schema({
  name: String,
  address: addressSchema
});
```

**22. Using Schema Options**

```javascript
const userSchema = new mongoose.Schema({
  name: String
}, {
  timestamps: true // Automatically add createdAt and updatedAt fields
});
```

**23. Using Custom Validation**

```javascript
const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    validate: {
      validator: function(v) {
        return v && v.length > 2;
      },
      message: 'Name must be longer than 2 characters'
    }
  }
});
```

**24. Using Indexes with Options**

```javascript
userSchema.index({ name: 1 }, { unique: true }); // Create a unique index on the 'name' field
```

**25. Using Query Helpers**

```javascript
User.countDocuments({ age: { $gte: 18 } }, (err, count) => {
  if (err) return console.error(err);
  console.log(`There are ${count} users with age greater than or equal to 18`);
});
```
