是什么?
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
就是一个数据库,这个数据库,存储的是json字符串类型的数据。支持 crud操作。
MongoDB 的设计目标是高性能、可扩展、易部署、易使用,存储数据非常方便。其主要功能特性如下。
(1)面向集合存储,容易存储对象类型的数据。在MongoDB 中数据被分组存储在集合中,集合类似RDBMS 中的表,一个集合中可以存储无限多的文档。
(2)模式自由,采用无模式结构存储。在MongoDB 中集合中存储的数据是无模式的文档,采用无模式存储数据是集合区别于RDBMS 中的表的一个重要特征。
(3)支持完全索引,可以在任意属性上建立索引,包含内部对象。MongoDB的索引和RDBMS 的索引基本一样,可以在指定属性、内部对象上创建索引以提高查询的速度。除此之外,MongoDB 还提供创建基于地理空间的索引的能力。
(4)支持查询。MongoDB 支持丰富的查询操作,MongoDB 几乎支持SQL中的大部分查询。
(5)强大的聚合工具。MongoDB 除了提供丰富的查询功能外,还提供强大的聚合工具,如count、group 等,支持使用MapReduce 完成复杂的聚合任务。
(6)支持复制和数据恢复。MongoDB 支持主从复制机制,可以实现数据备份、故障恢复、读扩展等功能。而基于副本集的复制机制提供了自动故障恢复的功能,确保了集群数据不会丢失。
(7)使用高效的二进制数据存储,包括大型对象(如视频)。使用二进制格式存储,可以保存任何类型的数据对象。
(8)自动处理分片,以支持云计算层次的扩展。MongoDB 支持集群自动切分数据,对数据进行分片可以使集群存储更多的数据,实现更大的负载,也能保证存储的负载均衡。
(9)支持Perl、PHP、Java、C#、JavaScript、Ruby、C 和C++语言的驱动程序,MongoDB 提供了当前所有主流开发语言的数据库驱动包,开发人员使用任何一种主流开发语言都可以轻松编程,实现访问MongoDB 数据库。
(10)文件存储格式为BSON(JSON 的一种扩展)。BSON 是对二进制格式的JSON 的简称,BSON 支持文档和数组的嵌套。
(11)可以通过网络访问。可以通过网络远程访问MongoDB 数据库。
基本概念:
(1)文档
文档是 MongoDB 中数据的基本单位,类似于关系数据库中的行(但是比行复杂)。多个键及其关联的值有序地放在一起就构成了文档。不同的编程语言对文档的表示方法不同
{“foo”: 3 ,“greeting”:“hello,world”}
文档中的值不仅可以是双引号中的字符串,也可以是其他的数据类型,例如,整型、布尔型等,也可以是另外一个文档,即文档可以嵌套。文档中的键类型只能是字符串。
(2)集合
集合就是一组文档,类似于关系数据库中的表。集合是无模式的,集合中的文档可以是各式各样的。例如,{“hello,word”:“Mike”}和{“foo”: 3},它们的键不同,值的类型也不同,但是它们可以存放在同一个集合中,也就是不同模式的文档都可以放在同一个集合中。用户可以灵活选择。
可以使用“.”按照命名空间将集合划分为子集合。虽然子集合没有任何特殊的地方,但是使用子集合组织数据结构清晰,这也是MongoDB 推荐的方法。
(3)数据库
MongoDB 中多个文档组成集合,多个集合组成数据库。一个MongoDB 实例可以承载多个数据库。它们之间可以看作相互独立,每个数据库都有独立的权限控制。在磁盘上,不同的数据库存放在不同的文件中。MongoDB 中存在以下系统数据库。
● Admin 数据库:一个权限数据库,如果创建用户的时候将该用户添加到admin 数据库中,那么该用户就自动继承了所有数据库的权限。
● Local 数据库:这个数据库永远不会被负责,可以用来存储本地单台服务器的任意集合。
● Config 数据库:当MongoDB 使用分片模式时,config 数据库在内部使用,用于保存分片的信息
为什么要用它?
特点:
它的特点是高性能、易部署、易使用,存储数据非常方便。主要功能特性有:
*面向集合存储,易存储对象类型的数据。
*模式自由。
*支持动态查询。
*支持完全索引,包含内部对象。
*支持查询。
*支持复制和故障恢复。
*使用高效的二进制数据存储,包括大型对象(如视频等)。
*自动处理碎片,以支持云计算层次的扩展性。
*支持RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
*文件存储格式为BSON(一种JSON的扩展)。
*可通过网络访问。
就是,支持动态查询,存储快吧,还可以存一些大的文件,效率什么的,不知道,感觉还行。现在刚使用,就这种感觉。
原因:
所谓“面向集合”(Collection-Oriented),意思是数据被分组存储在数据集中,被称为一个集合(Collection)。每个集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定义任何模式(schema)。Nytro MegaRAID技术中的闪存高速缓存算法,能够快速识别数据库内大数据集中的热数据,提供一致的性能改进。
模式自由(schema-free),意味着对于存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义。如果需要的话,你完全可以把不同结构的文件存储在同一个数据库里。
存储在集合中的文档,被存储为键-值对的形式。键用于唯一标识一个文档,为字符串类型,而值则可以是各种复杂的文件类型。我们称这种存储形式为BSON(Binary Serialized Document Format)。 [3]
1)网站实时数据处理。它非常适合实时的插入、更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
2)缓存。由于性能很高,它适合作为信息基础设施的缓存层。在系统重启之后,由它搭建的持久化缓存层可以避免下层的数据源过载。
3)高伸缩性的场景。非常适合由数十或数百台服务器组成的数据库,它的路线图中已经包含对MapReduce引擎的内置支持。
不适用的场景如下:
1)要求高度事务性的系统。
2)传统的商业智能应用。
3)复杂的跨文档(表)级联查询。
注意事项:
MongoDB服务端可运行在Linux、Windows或mac os x平台,支持32位和64位应用,默认端口为27017。推荐运行在64位平台,因为MongoDB在32位模式运行时支持的最大文件尺寸为2GB。
怎么用?
一,安装篇
1.安装
https://www.mongodb.com/download-center?jmp=nav#community
2.安装之后我就放到”D盘“,改下文件夹名字为”mongodb“(data,etc,logs三个文件夹为后面自己创建的,稍后说明)。
创建 D:\mongdb\data\db ①:启动之前,我们要给mongodb指定一个文件夹,这里取名为”db",用来存放mongodb的数据。
D:\mongdb\data\log
3.开启服务
打开cmd命令行窗口,切换到D:\mongodb\bin 目录执行如下命令
mongod --dbpath D:\MongoDB\data
这时命令行窗口会打印一些启动信息,最后一行显示为如下信息时表示启动成功了.
这时在浏览器输入http://localhost:27017/可以看到显示信息
目前mongodb服务已经启动了,关闭这个cmd窗口,会自动关闭服务。
下次可以用同样的步骤重新开启服务。(不推荐)
4.开启本地服务
事实上每次通过命令行启动Mongo是痛苦的,因此我们需要建立一个永久性服务,这就需要我们把Mongo加入到Windows本地服务中去。继续回到cmd,执行(会创建一个存放日志的文件夹及日志文件,data文件夹路径为本机data的路径):
mongod.exe --logpath D:\mongodb\logs\mongodb.log --logappend --dbpath D:\mongodb\data --directoryperdb --serviceName MongoDB --install
服务创建完成之后,默认是停止状态,我们需要手动打开服务,用命令,net start MongoDB,开启服务。(如果不生效,也可以自己打开任务管理器,找到相关服务,手动打开。如图表示mongodb服务已启动)
二,基础入门篇
mongodb中有三元素:数据库,集合,文档,其中“集合”
就是对应关系数据库中的“表”,“文档”对应“行”。
“增删查改“操作
我们再开一个cmd,输入mongo命令打开shell,其实这个shell就是mongodb的客户端,
同时也是一个js的编译器,默认连接的是“test”数据库。
show dbs 查看当前的数据库
use databaseName 选库
show tables/collections 查看当前库下的collection
如何创建库?
Mongodb的库是隐式创建,你可以use 一个不存在的库
然后在该库下创建collection,即可创建库
db.createCollection(‘collectionName’)
collection允许隐式创建
Db.collectionName.insert(document);
db.collectionName.drop()
删除collection
db.dropDatabase();
删除database
注意,这里,创建了库后,需要添加数据,才能查看自己新创建的库。
<1> insert 操作
这里就取集合名为“person”,要注意的就是文档是一个json的扩展(Bson)形式。
db.person.insert({"name":"kack","age":20})
db.person.insert({"name":"joe","age":25})
<2> find 操作
我们将数据插入后,肯定是要find出来,不然插了也白插,这里要注意两点:① “_id": 这个字段是数据库默认给我们加的GUID,目的就是保证数据的唯一性。
② 严格的按照Bson的形式书写文档,不过也没关系,错误提示还是很强大的。
db.person.find()
查询所有
db.person.find({"name":joe})
<3> update操作
update方法的第一个参数为“查找的条件”,第二个参数为“更新的值"
db.person.update({"name":"joe"},{"name":"joe","age":"30"})
<4> remove操作
remove中如果不带参数将删除所有数据, ,在mongodb中是一个不可撤回的操作,小心。
三,细说增删查改
一: Insert操作
文档是采用“K-V”格式存储的,JSON里面Value
可能是“字符串”,可能是“数组”,又有可能是内嵌的一个JSON对象,相同的方式也适合于BSON。
常见的插入操作也就两种形式存在:“单条插入”和“批量插入”。
① 单条插入
mongo命令打开的是一个javascript shell。所以js的语法在这里面都行得通。
var single = ("name":"jack","password":"12345","age":20)
db.user.insert(single);
② 批量插入
由于mongodb中没有提供给shell的“批量插入方法”,没关系,各个语言的driver都打通
了跟mongodb内部的批量插入方法,因为该方法是不可或缺的,如果大家非要模拟下批量插入的话,可以自己写了for循环,里面就是insert。
二:Find操作
日常开发中,我们玩查询,玩的最多的也就是二类:
①: >, >=, <, <=, !=, =。
②:And,OR,In,NotIn
mongodb里面都封装
<1>"$gt", "$gte", "$lt", "$lte", "$ne", "没有特殊关键字",这些跟上面是一一对应的,举几个例子。
$gt:>
$gte:>=
$eq: =
$ne: !=
$lt: <
$lte: <=
$in: in(后面的值为bson对象数组)
$nin: not in(后面的值为bson对象数组)
四,与spring-date - MongoRepository 结合篇
maven项目
1.配置
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.10.1.RELEASE</version>
</dependency>
2.配置Mongodb配置文件 MongoCOnfig.java
package com.bbt.log.common.framework;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import com.mongodb.Mongo;
// http://zoeminghong.github.io/2016/07/05/mongo20160705/
@Configuration
@EnableMongoRepositories(basePackages = "com.xiaoqiang.log.mongo.repository")
public class MongoConfig {
// 域名 ip
public static String MONGO_HOST = "127.0.0.1";
// 所连的mongodb服务器
public static String MONGO_DATABASE_NAME = "xiaoqiang";
// 注册bean
@Bean
public MongoClientFactoryBean mongo() {
MongoClientFactoryBean mongo = new MongoClientFactoryBean();
mongo.setHost("127.0.0.1");
mongo.setPort(27017);
// MongoCredential credential=MongoCredential.createCredential(env.getProperty("mongo.username"),
// "OrdersDB",env.getProperty("mongo.password").toCharArray());
// mongo.setCredentials(new MongoCredential[]{credential});
return mongo;
}
// 注册bean MongoTempalte对象
@Bean
public MongoOperations mongoTemplate(Mongo mongo) {
return new MongoTemplate(mongo, MONGO_DATABASE_NAME);
}
}
3.仓库集成
package com.xiaoqiang.log.client.event;
import java.util.Date;
/**
* Created by xiaoqiang on 17/3/23.
*/
public class UserLoginEvent {
private String sellerNick;
public UserLoginEvent() {
this.eventType = EventTypeEnum.USER_LOGIN.value();
}
public String getSellerNick() {
return sellerNick;
}
public void setSellerNick(String sellerNick) {
this.sellerNick = sellerNick;
}
}
如果只是用简单的CRUD操作,则不需要添加其他的方法,MongoRepository提供的方法足够我们使用。
package com.xiaoqiang.log.mongo.repository;
import com.bbt.log.client.event.UserLoginEvent;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface UserLoginRepository extends MongoRepository<UserLoginEvent, String> {
}
我们打开这个MongoRepository仓库源码
/*
* Copyright 2010-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.mongodb.repository;
import java.io.Serializable;
import java.util.List;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
/**
* Mongo specific {@link org.springframework.data.repository.Repository} interface.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Thomas Darimont
* @author Mark Paluch
*/
@NoRepositoryBean
public interface MongoRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
*/
@Override
<S extends T> List<S> save(Iterable<S> entites);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll()
*/
@Override
List<T> findAll();
/*
* (non-Javadoc)
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
*/
@Override
List<T> findAll(Sort sort);
/**
* Inserts the given entity. Assumes the instance to be new to be able to apply insertion optimizations. Use
* the returned instance for further operations as the save operation might have changed the entity instance
* completely. Prefer using {@link #save(Object)} instead to avoid the usage of store-specific API.
*
* @param entity must not be {@literal null}.
* @return the saved entity
* @since 1.7
*/
<S extends T> S insert(S entity);
/**
* Inserts the given entities. Assumes the given entities to have not been persisted yet and thus will optimize the
* insert over a call to {@link #save(Iterable)}. Prefer using {@link #save(Iterable)} to avoid the usage of store
* specific API.
*
* @param entities must not be {@literal null}.
* @return the saved entities
* @since 1.7
*/
<S extends T> List<S> insert(Iterable<S> entities);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)
*/
@Override
<S extends T> List<S> findAll(Example<S> example);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Sort)
*/
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
可以知道,已经提供了,基础的crud操作。
3.利用MongoRepository中的查询进行操作
首先,在service层中,将PersonRepository注入到service类中
(重要)java 操作mongoDB(DBobject,非spring data)
DBCollection类:指定数据库中指定集合的实例,提供了增删改查等一系列操作。在关系型数据库中,对数据的增删改查操作是 建立在表的基础上的,在mongodb中是建立在集合的基础上进行的。
DBObject接口:DBObject是键值的映射,因此,可以将DBObject的实现类作为查询的返回结果,也可以作为查询条件
DBCursor:游标,返回结果的集合。
package com.bbt.log.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.mongodb.core.MongoOperations;
import com.xiaoqiang.log.client.enums.LoginFromEnum;
import com.xiaoqiang.log.model.query.RecordBbtCustomerLogQuery;
import com.xiaoqiang.log.model.result.RecordBbtCustomerLogResultModel;
import com.xiaoqiang.log.service.RecordBbtCustomerLogService;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
public class RecordBbtCustomerLogServiceImpl implements RecordBbtCustomerLogService {
private Log LOG = LogFactory.getLog(RecordBbtCustomerLogServiceImpl.class);
@Resource
private MongoOperations mongoTemplate;
@Override
public RecordBbtCustomerLogResultModel queryUserLoginCount(RecordBbtCustomerLogQuery query) {
RecordBbtCustomerLogResultModel recordBbtCustomerLogResultModel = new RecordBbtCustomerLogResultModel();
recordBbtCustomerLogResultModel.setStatus(1);
recordBbtCustomerLogResultModel.setMsg("请求处理成功");
List dbCursor = null;
DBObject dBObject = null;
try {
dBObject = new BasicDBObject(); // setup the query criteria 设置查询条件
dBObject.put("lastLoginTime", (new BasicDBObject("$gte", query.getStartTime())).append("$lte", query.getEndTime()));
dBObject.put("from", (new BasicDBObject("$eq", LoginFromEnum.PC_WEB.value())));
dbCursor = mongoTemplate.getCollection("userLoginEvent").distinct("sellerNick", dBObject);
if (null == dbCursor || dbCursor.isEmpty()) {
recordBbtCustomerLogResultModel.setPcWebCount(0);
} else {
recordBbtCustomerLogResultModel.setPcWebCount(dbCursor.size());
}
dBObject.put("from", (new BasicDBObject("$eq", LoginFromEnum.PC_QN.value())));
dbCursor = mongoTemplate.getCollection("userLoginEvent").distinct("sellerNick", dBObject);
if (null == dbCursor || dbCursor.isEmpty()) {
recordBbtCustomerLogResultModel.setPcQnCount(0);
} else {
recordBbtCustomerLogResultModel.setPcQnCount(dbCursor.size());
}
dBObject.put("from", (new BasicDBObject("$eq", LoginFromEnum.MOBILE_QN.value())));
dbCursor = mongoTemplate.getCollection("userLoginEvent").distinct("sellerNick", dBObject);
if (null == dbCursor || dbCursor.isEmpty()) {
recordBbtCustomerLogResultModel.setMobileQnCount(0);
} else {
recordBbtCustomerLogResultModel.setMobileQnCount(dbCursor.size());
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
recordBbtCustomerLogResultModel.setStatus(0);
recordBbtCustomerLogResultModel.setMsg("请求处理失败");
}
return recordBbtCustomerLogResultModel;
}
}
// 4.查询所有的数据:
public List<Person> queryAll() throws Exception {
return personRepository.findAll();
}
5.根据实体类中的属性进行查询:
当需要根据实体类中的属性查询时,MongoRepository提供的方法已经不能满足,我们需要在PersonRepository仓库中定义方法,定义方法名的规则为:find + By + 属性名(首字母大写)
package com.xiaoqiang.log.mongo.repository;
import com.xiaoqiang.log.client.event.UserLoginEvent;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface UserLoginRepository extends MongoRepository<UserLoginEvent, String> {
// public List<UserLoginEvent> findBySellerNick(String sellerNick)
}
注意:
查询语句
db.getCollection('pageAccessEvent').find({"gmtCreate":{"$gte" : ISODate("2019-03-13T00:00:00.000Z"),"$lte" : ISODate("2019-03-13T23:59:59.591Z") }})
mongodb默认时间,是标准时间,查询的时候要加8个小时,任意的转换都是+8,均需要减8个小时,搞了一下午
多条查询
db.getCollection('userLoginEvent').find({
"sellerNick":"tb979768_44",
"loginTime":{"$gte" : ISODate("2019-09-18T00:00:00.000Z"),"$lte" : ISODate("2019-09-18T23:59:59.591Z") }
})
db.getCollection('userChargeEvent').find({ "sellerNick":"tb979768_44"}).sort({"_id":-1}).limit(1)
倒序查询 最后一条
总结:到这里,基本上,mongodb的使用,安装,集成java,等等,都可以了。 后续的再说。
参考资料:
https://blog.youkuaiyun.com/novodexx/article/details/79329431
{
"collection": "MetricModuleEvent",
"aggregate": [
{
"$match": {
"dateNo": {{ dateNo }}
}
},
{
"$lookup": {
"from": "pageMappingModuleEvent",
"localField": "page",
"foreignField": "url",
"as": "a"
}
},
{
"$unwind": "$a"
},
{
"$addFields": {
"name": "$a.module"
}
},
{
"$project": {
"dateNo": 1,
"pv": 1,
"uv": 1,
"name": 1,
"_id": 0,
"page": 1
}
}
]
}