mongodb常见疑问

本文主要是分享一些关于使用mongodb方面的问题,后续会慢慢补充。如还不了解mongodb,请参阅《入门手册》。

目录

1. 如何快速熟悉各种命令?

2. 如何处理文档的引用关系?

3. 不支持事务,是不是就不可接受?

4. ObjectId是个什么东东?

5. 有Int的自动增长类型吗?

6.库名文档名命名规范


1. 如何快速熟悉各种命令?

使用runCommand执行,可参考7.5

2. 如何处理文档的引用关系?

MongoDB 中的文档各种关系,官方推荐的思想是整存整取(内嵌文档),但如果内嵌文档在不断增加,数据量不断变大,会影响读写性能。所有引用式关系也是必要的,可通过引用文档的 id 字段来建立关系。

{
   "_id":ObjectId("52ffc33cd85242f436000001"),
   "contact": "987654321",
   "dob": "01-01-1991",
   "name": "Tom Benzamin",
   "address_ids": [
      ObjectId("52ffc4a5d85242602e000000"),
      ObjectId("52ffc4a5d85242602e000001")
   ]
}
var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1})
var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})

3. 不支持事务,是不是就不可接受?

mongodb不支持事务,但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操作。所谓原子操作就是要么这个文档保存到Mongodb,要么没有保存到Mongodb,不会出现查询到的文档没有保存完整的情况。

4. ObjectId是个什么东东?

ObjectId 是一个12字节 BSON 类型数据,有以下格式:

  • 前4个字节表示时间戳
  • 接下来的3个字节是机器标识码
  • 紧接的两个字节由进程id组成(PID)
  • 最后三个字节是随机数。

MongoDB中存储的文档必须有一个"_id"键。这个键的值可以是任何类型的,默认是个ObjectId对象。

5. 有Int的自动增长类型吗?

MongoDB 没有像 SQL 一样有自动增长的功能,但在某些情况下,我们可能需要实现 ObjectId 自动增长功能。

//切换数据库
use mydb
//创建文档idGenarator
db.idGenarator.insert({_id:"transProductId",sequence_value:0})
db.idGenarator.find()    //查询document
//创建函数
db.system.js.insert({
	_id: "getNextSequenceValue",
	value: function getNextSequenceValue(sequenceName) {
		var sequenceDocument = db.idGenarator.findAndModify({
				query: {
					_id: sequenceName
				},
				update: {
					$inc: {
						sequence_value: 1
					}
				},
				new: true
			});
		return sequenceDocument.sequence_value;
	}
})
db.system.js.find().pretty()    //查看函数创建信息
getNextSequenceValue('transProductId');    //执行或使用db.eval
//插入时_id自增
db.products.insert({"_id":getNextSequenceValue("productid"),"product_name":"Samsung S3"})

方式1

按这样的思路去实现,如何使用呢?直接执行函数,参阅官方“Script Operations

ScriptOperations operations = mongoTemplate.scriptOps();
Object result = operations.call("getNextSequenceValue", "transProductId");
System.out.println("result:" + result);

在我本地是可以运行的,但是在我们测试环境【db.version】->3.2.12,会报这样的一个错:

not authorized on omsopa to execute command { $eval: "getNextSequenceValue('transProductId')", args: [] }'

最后反复和dba确认,用户权限也是没有问题的。

方式2

直接使用mongoTemplate.findAndModify

@Component
public class IdGenaratorVisitor {
    @Autowired
    private MongoTemplate mongoTemplate;

    /**
     * 获取自增Id
     *
     * @param groupName
     * @return
     */
    public Long getNextId(String groupName) {
        Query query = new Query(Criteria.where(IdGenaratorDomain.ID_COL_NAME).is(IdGroup.TransProduct.getName()));
        Update update = new Update();
        update.inc(IdGenaratorDomain.SEQ_COL_NAME, 1);
        FindAndModifyOptions options = new FindAndModifyOptions();
        options.upsert(true);
        options.returnNew(true);
        IdGenaratorDomain seq = mongoTemplate.findAndModify(query, update, options, IdGenaratorDomain.class);
        return seq.getSequenceValue();
    }


    @Document(collection = "idGenarator")
    public class IdGenaratorDomain {
        private static final String ID_COL_NAME = "_id";
        private static final String SEQ_COL_NAME = "sequence_value";
        @org.springframework.data.mongodb.core.mapping.Field(SEQ_COL_NAME)
        private Long sequenceValue;

        public Long getSequenceValue() {
            return sequenceValue;
        }

        public void setSequenceValue(Long sequenceValue) {
            this.sequenceValue = sequenceValue;
        }
    }
}

在jpa中如何实现呢?

Spring Data MongoDB是有生命周期的,通过继承AbstractMongoEventListener类来实现监听,它内部有onBeforeConvert,onBeforeSave,onAfterSave,onAfterLoad,onAfterConvert,onAfterDelete,onBeforeDelete。

/**
 * 如果需要生成自增id可以标注
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface IdAutoInc {
    IdGroup value();
}
/**
 * id枚举值:每个枚举值都会从1开始生成
 */
public enum IdGroup {
    TransProduct;

    public String getName() {
        switch (this.ordinal()) {
            case 0:
                return "transProductId";
            default:
                return "";
        }
    }
}
/**
 * id生成document类型约束,需继承才会执行生成
 */
public interface IdIncDomain {
}
/**
 * 处理Mongo document新增id自增问题
 */
@Component
public class MongoFieldFillOnSave extends AbstractMongoEventListener<Object> {
    private static Map<String, IdField> idCachePool = Maps.newConcurrentMap();
    @Autowired
    private IdGenaratorVisitor idGenaratorVisitor;

    @Override
    public void onBeforeConvert(BeforeConvertEvent<Object> event) {
        Object source = event.getSource();
        if (source != null) {
            Class<?> sourceClz = source.getClass();
            IdField idFld = idCachePool.get(sourceClz.getName());
            if (idFld == null) {
                //类型规约
                if (!ClassUtils.getAllInterfacesForClassAsSet(Student.class).contains(IdIncDomain.class)){
                    return;
                }
                ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {
                    @Override
                    public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                        ReflectionUtils.makeAccessible(field);
                        IdAutoInc idAnno = field.getAnnotation(IdAutoInc.class);
                        if (idAnno != null) {
                            IdField idField = new IdField(field, idAnno.value());
                            idFieldFill(source, idField);
                            idCachePool.putIfAbsent(sourceClz.getName(), idField);
                        }
                    }
                });
            } else {
                idFieldFill(source, idFld);
            }
        }
    }
    private void idFieldFill(Object source, IdField idFld) {
        try {
            Long id = idGenaratorVisitor.getNextId(idFld.getIdGroup().getName());
            ReflectionUtils.makeAccessible(idFld.getField());
            idFld.getField().set(source, id);
        } catch (IllegalAccessException e) {
            throw new BusinessRuntimeException("mongo ID AutoGenarator error:" + e.getMessage());
        }
    }

    /**
     * field缓存实例
     */
    public class IdField {
        private Field field;
        private IdGroup idGroup;
        public IdField(Field field, IdGroup idGroup) {
            this.field = field;
            this.idGroup = idGroup;
        }
        public Field getField() {
            return field;
        }
        public void setField(Field field) {
            this.field = field;
        }
        public IdGroup getIdGroup() {
            return idGroup;
        }
        public void setIdGroup(IdGroup idGroup) {
            this.idGroup = idGroup;
        }
    }
}
/**
 *
 * test
 */
@Document(collection = "myStudent")
public class Student implements Serializable,IdIncDomain {
    @IdAutoInc(IdGroup.TransProduct)
    @Id
    private long id;
    private String name;

    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
public interface  StudentRepository extends MongoRepository<Student, Long>{
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class Mongo_test {   
    @Autowired
    private StudentRepository studentRepository;
    @Test
    public void go_insert() {
        for (int i = 0; i < 2; i++) {
            Student student = new Student();
            student.setName("alex" + i);
            Student result = studentRepository.save(student);
            System.out.println("result:" + result.getId());
        }
    }
}

6.库名文档名命名规范

数据库命名

  • 不能为空字符串(" ")
  • 不能$开头
  • 不得含有' '(空格)、.、$、/、\和\0 (空字符)
  • 数据库名区分大小写(建议数据库名全部使用小写)
  • 数据库名最长为64个字节
  • 不要与系统保留的数据库名相同,这写数据库包括:admin,local,config等

集合命名

  • 集合名不能为空字符串(" ")
  • 不能包含\0或空字符,这个字符表示键的结尾
  • 集合名不能包含$字符(注:可包含 . 点号),除非你要访问这种系统创建的集合
  • 集合名不能以"system."开头,此前缀是系统本身保留的

命名空间

  • 命名空间的长度不可超过100个字节
  • 组织子集合的方式就是使用“.”,分隔不同命名空间的子集合

在MongoDB中,为了使组织结构更清晰更方便管理,使用子集合来组织数据非常高效,值得推荐。比如一个具有博客功能可能包含两个集合,分别是blog.posts和blog.authors,但blog集合(这个集合甚至不需要存在)跟它的两个子集合没有任何关系。

文件键命名

  • _id 是系统保留关键字, 是默认主键, 在集合中必需唯一, 且不可更改.
  • 下划线"_"开头的键是保留的(不是严格要求的)
  • 键不能包含\0或空字符,这个字符表示键的结尾
  • .和$尽量不要用,只有在特定环境下才能使用
  • 分大小写且不能重复,如:{Aaa:1, aaa:2}
<think>好的,我现在需要帮助用户找到关于MongoDB的入门教程和学习资料。首先,用户之前的问题提到了想查找教程或学习资料,而我的回答需要参考提供的引用内容,确保信息准确。 首先,查看用户提供的引用内容。引用[1]提到了MongoDB的应用场景,比如社交、游戏、物流等,这可能对用户理解MongoDB的用途有帮助。引用[2]和[3]涉及安装步骤和基本操作,这些是入门的关键部分。用户需要的是入门教程,所以应该从安装、基本命令、数据操作等方面入手。 接下来,我需要确保回答结构清晰,分步骤说明。可能需要包括环境搭建、基本概念、CRUD操作、索引、聚合等。同时,用户可能对实际应用场景感兴趣,可以结合引用[1]提到的例子,让学习更有针对性。 还要注意用户可能遇到的问题,比如安装时的权限设置,数据目录创建等,引用[2]中的命令需要正确无误。另外,引用[3]提到区分大小写,这也是需要注意的细节,应该在教程中强调。 用户可能需要实践指导,比如代码示例,所以插入文档、查询等操作的具体命令要准确。同时,提供学习资源链接,如官方文档、中文社区,帮助用户深入学习。 最后,生成的相关问题需要覆盖常见疑问,比如应用场景、性能优化、数据建模等,这些可以引导用户进一步探索。需要确保问题与入门教程相关,并且基于引用内容中的信息。</think>### MongoDB入门学习指南 #### 一、环境搭建 1. **下载安装** MongoDB提供Windows/Linux/macOS版本,建议选择社区版。以macOS为例: ```bash # 创建默认数据存储目录并授权[^2] sudo mkdir -p /data/db sudo chmod -R 777 /data/db/ # 解压安装包后启动服务端和客户端[^2] ./bin/mongod # 启动服务 ./bin/mongo # 进入交互式Shell ``` #### 二、核心概念 1. **文档结构** MongoDB使用BSON格式(类似JSON)存储数据,例如: ```javascript { "userName": "Jack", "age": 20, "hobbies": ["coding", "hiking"] } ``` 2. **集合与数据库** - 数据库(Database)包含多个集合(Collection) - 集合类似SQL中的表,但不需要预定义结构 #### 三、基础操作 1. **插入数据** ```javascript db.books.insertMany([ {"userName":"Jack","age":20}, {"userName":"Tom"} // 允许字段缺失[^3] ]) ``` 2. **查询数据** ```javascript db.users.find({"age": {$gt: 18}}) // 查询年龄>18的用户 ``` 3. **更新数据** ```javascript db.users.updateOne( {"userName":"Jack"}, {$set: {"status": "active"}} ) ``` 4. **创建索引** ```javascript db.orders.createIndex({"orderDate": 1}) // 1为升序索引 ``` #### 四、应用场景实践 根据引用[1]的典型用例: 1. **游戏场景** ```javascript // 存储玩家数据(内嵌装备信息) db.players.insertOne({ "playerId": 1001, "equipments": [ {"name": "sword", "attack": 50}, {"name": "shield", "defense": 80} ] }) ``` 2. **物流场景** ```javascript // 存储订单轨迹(使用数组记录状态变更) db.orders.insertOne({ "orderNo": "SF20230715", "tracking": [ {"time": "2023-07-15 09:00", "status": "已揽收"}, {"time": "2023-07-16 14:30", "status": "运输中"} ] }) ``` #### 五、学习资源推荐 1. **官方文档** [MongoDB官方手册](https://docs.mongodb.com/manual/)(含交互式教程) 2. **中文教程** - [MongoDB大学免费课程](https://university.mongodb.com/) - [中文社区](https://mongoing.com/)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值