MongoDB

发布于:2025-05-12 ⋅ 阅读:(27) ⋅ 点赞:(0)

以下是 MySQL 和 MongoDB 有差异的地方的对比表格:

概念 MySQL MongoDB
表(Table) 集合(Collection)
字段/列 字段/列(Column),结构固定 字段(Field),结构灵活,可动态扩展
记录/行 记录/行(Row),数据必须符合表结构 文档(Document),以BSON格式存储,支持嵌套
主键 主键(Primary Key),通常是自增的id _id字段,默认为ObjectId类型,非自增
查询语言 SQL(Structured Query Language) MQL(MongoDB Query Language)
数据模型 固定模式的关系型数据模型 灵活模式的文档型数据模型
事务支持 完全支持ACID属性 支持单文档原子操作;4.0版本后支持多文档事务
关系处理 使用外键实现表之间的关联 嵌入式(Embedding)或引用(Referencing)表示关系
存储格式 行存储格式 BSON(类似于JSON)

这里是详细的 MongoDB 语法总结,每个部分都有清晰的 说明示例,帮助你快速掌握 MongoDB 查询、更新、插入、删除、索引、地理查询等操作。


创建或切换数据库

test> use location   // 切换或创建数据库
switched to db location

1. 查询 (find)

MongoDB 允许使用 find() 方法查询集合中的数据,并支持条件筛选、排序、分页等操作。

查询全部数据

查询 vehicle_location 集合中的所有数据:

db.vehicle_location.find({})
查询匹配字段
  • 单条件查询
    查询 vehicleId"1820377198820880384" 的车辆信息:
db.vehicle_location.find({ vehicleId: "1820377198820880384" })
  • 多条件查询
    查询tenantId=3, updateTime大于等于2024-07-01的,小于2025-07-02的数据
db.vehicle_location.find({ 
    tenantId: "3",
    updateTime: {
        $gte: "2024-07-01",
        $lt: "2025-07-02"
    }
})
逻辑运算符

MongoDB 提供了一些常用的逻辑运算符:

操作符 作用 示例
$eq 等于 { age: { $eq: 18 } }
$ne 不等于 { age: { $ne: 18 } }
$gt 大于 { age: { $gt: 18 } }
$lt 小于 { age: { $lt: 18 } }
$gte 大于等于 { age: { $gte: 18 } }
$lte 小于等于 { age: { $lte: 18 } }
$in 在数组内 { vehicleId: { $in: ["1820377198820880384", "1822090759331909632"] } }
$nin 不在数组内 { vehicleId: { $nin: ["1820377198820880384"] } }

示例:查询 18 岁及以上的所有用户

db.users.find({ age: { $gte: 18 } })

查所有集合
show collections

在这里插入图片描述

2. 插入 (insert)

插入单条数据

vehicle_location 集合中插入一条新数据:

db.vehicle_location.insertOne({
  vehicleId: "1820377198820880384",
  vehicleNo: "甘A12456",
  location: [103.855549, 36.050249],
  updateTime: "2025-02-07T09:23:41"
})
插入多条数据
db.vehicle_location.insertMany([
  {
    vehicleId: "1820377198820880384",
    vehicleNo: "甘A12456",
    location: [103.855549, 36.050249],
    updateTime: "2025-02-07T09:23:41"
  },
  {
    vehicleId: "1822090759331909632",
    vehicleNo: "甘B56789",
    location: [103.857185, 36.054035],
    updateTime: "2025-02-07T09:24:41"
  }
])

3. 更新 (update)

更新单条数据

vehicleId"1820377198820880384"updateTime 改为 "2025-02-07T10:00:00"

db.vehicle_location.updateOne(
  { vehicleId: "1820377198820880384" },
  { $set: { updateTime: "2025-02-07T10:00:00" } }
)
更新多条数据

updateTime 早于 "2025-02-07T09:30:00" 的车辆全部更新为 "2025-02-07T09:30:00"

db.vehicle_location.updateMany(
  { updateTime: { $lt: "2025-02-07T09:30:00" } },
  { $set: { updateTime: "2025-02-07T09:30:00" } }
)

4. 删除 (delete)

删除集合
location> db.vehicleLocationBo.drop()
true
删除单条数据

删除 vehicleId"1820377198820880384" 的车辆:

db.vehicle_location.deleteOne({ vehicleId: "1820377198820880384" })
删除多条数据

删除 updateTime 早于 "2025-02-07T09:00:00" 的所有车辆:

db.vehicle_location.deleteMany({ updateTime: { $lt: "2025-02-07T09:00:00" } })

5. 排序 & 分页

排序

updateTime 降序 排列:

db.vehicle_location.find().sort({ updateTime: -1 })

updateTime 升序 排列:

db.vehicle_location.find().sort({ updateTime: 1 })
分页

跳过 10 条数据,获取 5 条数据:

db.vehicle_location.find().skip(10).limit(5)

6. 地理位置查询

$near 需要 2dsphere 索引,但$geoWithin不需要索引也能使用。

坐标格式:MongoDB GeoJSON 格式使用 [longitude, latitude](经度在前,纬度在后)。

距离单位:

maxDistance 单位为米(m)。

$geoNear 查询必须包含 spherical: true 来确保地球曲率计算。

$geoWithin

  • 查询经纬度500米内的数据
db.collection.find({
  location: {
    $geoWithin: {
      $centerSphere: [
        [经度, 纬度], // 替换为目标点的经纬度
        500 / 6378100 // 半径,单位是弧度(米转换为弧度)
      ]
    }
  }
});
  • 查找某个区域内的点,例如查询某个矩形区域中的点
db.places.find({
  location: {
    $geoWithin: {
      $box: [
        [116.4035, 39.9140],  // 左下角坐标
        [116.4050, 39.9160]   // 右上角坐标
      ]
    }
  }
});
  • 查询某个多边形区域内的点:
db.places.find({
  location: {
    $geoWithin: {
      $geometry: {
        type: "Polygon",
        coordinates: [
          [
            [116.4035, 39.9140],
            [116.4050, 39.9140],
            [116.4050, 39.9160],
            [116.4035, 39.9160],
            [116.4035, 39.9140] // 首尾坐标必须相同
          ]
        ]
      }
    }
  }
});

  • 判断点是否在区域内 ($geoIntersects)
db.areas.find({
  region: {
    $geoIntersects: {
      $geometry: { type: "Point", coordinates: [116.4040, 39.9150] }
    }
  }
});

$near

经纬度500米内的数据

db.collection.find({
  location: {
    $near: {
      $geometry: {
        type: "Point",
        coordinates: [经度, 纬度] // 替换为目标点的经纬度
      },
      $maxDistance: 500 // 单位是米
    }
  }
});

其它

MongoDB Shell

linux中用来连接mongo

linux安装MongoDB Shell

  • 1.1 添加 MongoDB 官方仓库
sudo tee /etc/yum.repos.d/mongodb-org.repo <<EOF
[mongodb-org-7.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/7/mongodb-org/7.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://pgp.mongodb.com/server-7.0.asc
EOF
  • 1.2 安装 ​​mongosh​​
sudo yum install -y mongodb-mongosh
  • 1…3 验证安装
mongosh --version

在这里插入图片描述

登陆
  • 默认直接输入mongosh,就会登录到本机端口为27017的mongo
mongosh
  • 如果端口改过,加上参数–port指定端口登陆
mongosh --port 38080

在这里插入图片描述

  • 如果远程的monggodb,则要加上ip和端口
mongosh --host <ip> --port <port>
  • 如果启用了身份验证,需要提供用户名、密码和认证数据库(通常是 ​​admin​​)
mongosh --host <hostname> --port <port> -u <username> -p <password> --authenticationDatabase <authDB>

例如

mongosh --host 192.168.1.100 --port 27017 -u myuser -p mypassword --authenticationDatabase admin
  • 如果已经登陆了,但是没有确认用户名密码,db.auth(用户名,密码)
kd> db.auth("zs","root")
{ ok: 1 }

SpringBoot集成MongoDb

引入依赖
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
java和mongodb交互
第一种,继承MongoRepository
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;

public interface UserRepository extends MongoRepository<User, String> {
    List<User> findByName(String name);
}
第二种,使用MongoTemplate
 @Autowired
    private MongoTemplate mongoTemplate;

    public List<User> findUsersByNameAndAge(String name, int age) {
        Query query = new Query();
        Criteria criteria = Criteria.where("name").is(name).and("age").is(age);
        query.addCriteria(criteria);

        return mongoTemplate.find(query, User.class);
    }

查不到数据,需要指定集合名称
在find的第三个参数指定find(query, User.class,""),或者在接收的实体上面使用@Document(value = "")指定,不然查不到。

示例
package com.dh.taxi.data.utils;


import com.dh.taxi.data.domain.bo.VehicleLocationBo;
import com.dh.taxi.data.domain.vo.VehicleLocationVo;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.domain.geo.Metrics;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 位置工具类
 */
@Repository
public class LocationUtils {

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 查询车辆位置信息
     * @param bo
     * @return
     */
    public List<VehicleLocationVo> getLocationList(VehicleLocationBo bo) {

        Query query = new Query();
        Criteria criteria = new Criteria();

        List<Criteria> criteriaList = new ArrayList<>();

        //String类型,等于该值的数据
        if (bo.getVehicleId() != null) {
            criteriaList.add(Criteria.where("vehicleId").is(bo.getVehicleId()));
        }

        if (bo.getVehicleNo() != null) {
            criteriaList.add(Criteria.where("vehicleNo").is(bo.getVehicleNo()));
        }

        // 时间类型,查询指定时间段,mongo中的数据的格式:ISODate('2025-05-09T02:20:39.566Z')
        if(bo.getIntervalTimeSeconds() != null ){
            //当前时间
            Instant now = Instant.now();
            //默认30s,30s内
            Instant tenSecondsAgo = now.minus(bo.getIntervalTimeSeconds(), java.time.temporal.ChronoUnit.SECONDS);
            //当前时间30秒内的数据
            criteriaList.add(Criteria.where("updateTime").gte(tenSecondsAgo).lte(now));
        }

        //  地理位置坐标,坐标Coordinate经纬度,半径RadiusMeter米的数据
        if (!CollectionUtils.isEmpty(bo.getCoordinate())) {
            List<Double> coordinate = bo.getCoordinate();
            Point center = new Point(coordinate.get(0), coordinate.get(1));
            Distance distance = new Distance(bo.getRadiusMeter(), Metrics.METERS); // 默认1000 米
            criteriaList.add(Criteria.where("coordinate").nearSphere(center).maxDistance(distance.getNormalizedValue()));
        }

        // 如果有条件就拼接
        if (!criteriaList.isEmpty()) {
            criteria.andOperator(criteriaList.toArray(new Criteria[0]));
            query.addCriteria(criteria);
        }

        return mongoTemplate.find(query, VehicleLocationVo.class);
    }

    /**
     * 上传位置信息
     *
     * @return
     */
    public VehicleLocationBo uploadLocation(VehicleLocationBo bo) {
        bo.setUpdateTime(LocalDateTime.now());
        return mongoTemplate.insert(bo);
    }

}

删除
  • 常用删除方法
方法名 说明
remove(Query query, Class<T> entityClass) 根据条件删除匹配的数据(可以删除多条)
remove(Query query, String collectionName) 指定集合删除(不绑定实体类)
findAndRemove(Query query, Class<T> entityClass) 查找并删除一条数据(返回删除的实体)

  • 假设你要删除 name = "张三" 的数据:
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final MongoTemplate mongoTemplate;

    public UserService(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public void deleteUserByName(String name) {
        Query query = new Query(Criteria.where("name").is(name));
        mongoTemplate.remove(query, User.class);  // 默认使用 User 映射的集合
    }
}

  • 如果你只想删除一条数据(匹配的第一条):
User removedUser = mongoTemplate.findAndRemove(query, User.class);

  • 删除整个集合(清空表):
mongoTemplate.dropCollection(User.class);
// 或者指定集合名
mongoTemplate.dropCollection("user");

工具类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Optional;

@Component
public class MongoTemplateUtil {

    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 插入单个数据到MongoDB集合
     * 
     * @param entity 要插入的实体对象
     * @param <T> 实体类型
     * @return 插入后的实体对象
     */
    public <T> T insert(T entity) {
        return mongoTemplate.insert(entity);
    }

    /**
     * 批量插入数据到MongoDB集合
     * 
     * @param entities 要插入的实体对象列表
     * @param <T> 实体类型
     * @return 插入后的实体对象列表
     */
    public <T> List<T> insertAll(List<T> entities) {
        return mongoTemplate.insertAll(entities);
    }

    /**
     * 更新MongoDB集合中的数据
     * 
     * @param query 查询条件
     * @param entity 更新后的实体对象
     * @param entityClass 实体类类型
     * @param <T> 实体类型
     */
    public <T> void update(Query query, T entity, Class<T> entityClass) {
        mongoTemplate.findAndModify(query, entity, entityClass);
    }

    /**
     * 根据条件查询单条数据
     * 
     * @param query 查询条件
     * @param entityClass 实体类类型
     * @param <T> 实体类型
     * @return 查询到的单条数据(如果存在)
     */
    public <T> Optional<T> findOne(Query query, Class<T> entityClass) {
        T result = mongoTemplate.findOne(query, entityClass);
        return Optional.ofNullable(result);
    }

    /**
     * 根据条件查询多条数据
     * 
     * @param query 查询条件
     * @param entityClass 实体类类型
     * @param <T> 实体类型
     * @return 查询到的所有数据
     */
    public <T> List<T> find(Query query, Class<T> entityClass) {
        return mongoTemplate.find(query, entityClass);
    }

    /**
     * 根据ID查询数据
     * 
     * @param id 数据的ID
     * @param entityClass 实体类类型
     * @param <T> 实体类型
     * @return 查询到的数据(如果存在)
     */
    public <T> Optional<T> findById(Object id, Class<T> entityClass) {
        T result = mongoTemplate.findById(id, entityClass);
        return Optional.ofNullable(result);
    }

    /**
     * 删除数据
     * 
     * @param query 查询条件
     * @param entityClass 实体类类型
     * @param <T> 实体类型
     */
    public <T> void delete(Query query, Class<T> entityClass) {
        mongoTemplate.remove(query, entityClass);
    }

    /**
     * 判断集合中是否存在符合条件的数据
     * 
     * @param query 查询条件
     * @param entityClass 实体类类型
     * @param <T> 实体类型
     * @return 如果存在符合条件的数据,返回true;否则返回false
     */
    public <T> boolean exists(Query query, Class<T> entityClass) {
        return mongoTemplate.exists(query, entityClass);
    }

    /**
     * 使用聚合查询MongoDB数据
     * 
     * @param query 聚合查询条件
     * @param entityClass 实体类类型
     * @param <T> 实体类型
     * @return 聚合查询结果列表
     */
    public <T> List<T> aggregate(Query query, Class<T> entityClass) {
        return mongoTemplate.aggregate(query, entityClass).getMappedResults();
    }

    /**
     * 根据条件查询并返回指定字段
     * 
     * @param query 查询条件
     * @param entityClass 实体类类型
     * @param fields 要返回的字段名(可变参数)
     * @param <T> 实体类型
     * @return 查询到的所有数据
     */
    public <T> List<T> findWithFields(Query query, Class<T> entityClass, String... fields) {
        if (!CollectionUtils.isEmpty(List.of(fields))) {
            query.fields().include(fields);
        }
        return mongoTemplate.find(query, entityClass);
    }
}

  • 测试
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;

import java.util.List;

@SpringBootTest
public class MongoTemplateUtilTest {

    @Autowired
    private MongoTemplateUtil mongoTemplateUtil;

    @Test
    public void testInsert() {
        User user = new User("john_doe", "John", "Doe", 30);
        User insertedUser = mongoTemplateUtil.insert(user);
        System.out.println("Inserted user: " + insertedUser);
    }

    @Test
    public void testInsertAll() {
        User user1 = new User("alice_smith", "Alice", "Smith", 25);
        User user2 = new User("bob_jones", "Bob", "Jones", 28);
        List<User> users = mongoTemplateUtil.insertAll(List.of(user1, user2));
        users.forEach(user -> System.out.println("Inserted user: " + user));
    }

    @Test
    public void testFind() {
        Query query = new Query(Criteria.where("lastName").is("Doe"));
        List<User> users = mongoTemplateUtil.find(query, User.class);
        users.forEach(user -> System.out.println("Found user: " + user));
    }

    @Test
    public void testDelete() {
        Query query = new Query(Criteria.where("firstName").is("John"));
        mongoTemplateUtil.delete(query, User.class);
        System.out.println("Deleted users with first name 'John'.");
    }

    @Test
    public void testExists() {
        Query query = new Query(Criteria.where("firstName").is("Alice"));
        boolean exists = mongoTemplateUtil.exists(query, User.class);
        System.out.println("Does user exist? " + exists);
    }

    @Test
    public void testFindWithFields() {
        Query query = new Query(Criteria.where("lastName").is("Doe"));
        List<User> users = mongoTemplateUtil.findWithFields(query, User.class, "firstName", "lastName");
        users.forEach(user -> System.out.println("Found user with specified fields: " + user));
    }
}

  • 实体
public class User {
    private String id;
    private String username;
    private String firstName;
    private String lastName;
    private int age;

    // Constructors, getters and setters
    public User(String username, String firstName, String lastName, int age) {
        this.username = username;
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    // Getters and Setters omitted for brevity
}


planner returned error :: caused by :: unable to find index for $geoNear query’ on server 192.168.26.128:27017. The full response is {“ok”: 0.0, “errmsg”: “error processing query: ns=location.vehicle_locationTree: $and\n vehicleId $eq “1871467348318228480”\n GEONEAR field=location maxdist=0.000156786 isNearSphere=1\nSort: {}\nProj: {}\n planner returned error :: caused by :: unable to find index for $geoNear query”, “code”: 291, “codeName”: “NoQueryExecutionPlans”}

重要内容:caused by :: unable to find index for $geoNear query,查询中使用了 $eq 和 $near(地理空间查询)组合,但是字段没有设置索引,设置索引就好了

db.集合名.createIndex({ "字段名": "2dsphere" })

网站公告

今日签到

点亮在社区的每一天
去签到