java 操作Mongodb
CRUD基础操作
Springboot 操作 MongoDB 有两种方式。
- 第一种方式是采用 Springboot 官方推荐的 JPA 方式,这种操作方式,使用简单但是灵活性比较差。
- 第二种方式是采用 Spring Data MongoDB 封装的 MongoDB 官方 Java 驱动 MongoTemplate 对 MongoDB 进行操作,这种方式非常灵活,能满足绝大部分需求。
本文将采用第二种方式进行介绍!
插入文档
MongoTemplate提供了insert()方法,用于插入文档,示例代码如下:
- 用于插入文档
没指定集合名称时,会取@Document注解中的集合名称
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 插入文档
* @throws Exception
*/
@Test
public void insert() throws Exception {
Person person =new Person();
person.setId(1l);
person.setUserName("张三");
person.setPassWord("123456");
person.setCreateTime(new Date());
mongoTemplate.insert(person);
}
}
- 自定义集合名称,插入文档
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 自定义集合,插入文档
* @throws Exception
*/
@Test
public void insertCustomCollection() throws Exception {
Person person =new Person();
person.setId(1l);
person.setUserName("张三");
person.setPassWord("123456");
person.setCreateTime(new Date());
mongoTemplate.insert(person, "custom_person");
}
}
- 自定义集合,批量插入文档
如果采用批量插入文档,必须指定集合名称
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 自定义集合,批量插入文档
* @throws Exception
*/
@Test
public void insertBatch() throws Exception {
List<Person> personList = new ArrayList<>();
Person person1 =new Person();
person1.setId(10l);
person1.setUserName("张三");
person1.setPassWord("123456");
person1.setCreateTime(new Date());
personList.add(person1);
Person person2 =new Person();
person2.setId(11l);
person2.setUserName("李四");
person2.setPassWord("123456");
person2.setCreateTime(new Date());
personList.add(person2);
mongoTemplate.insert(personList, "custom_person");
}
}
存储文档
MongoTemplate提供了save()方法,用于存储文档。
在存储文档的时候会通过主键ID进行判断,如果存在就更新,否则就插入,示例代码如下:
- 存储文档,如果没有插入,否则通过主键ID更新
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 存储文档,如果没有插入,否则更新
* @throws Exception
*/
@Test
public void save() throws Exception {
Person person =new Person();
person.setId(13l);
person.setUserName("八八");
person.setPassWord("123456");
person.setAge(40);
person.setCreateTime(new Date());
mongoTemplate.save(person);
}
}
- 自定义集合,存储文档
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 自定义集合,存储文档
* @throws Exception
*/
@Test
public void saveCustomCollection() throws Exception {
Person person =new Person();
person.setId(1l);
person.setUserName("张三");
person.setPassWord("123456");
person.setCreateTime(new Date());
mongoTemplate.save(person, "custom_person");
}
}
更新文档
MongoTemplate提供了updateFirst()和updateMulti()方法,用于更新文档,示例代码如下:
- 更新文档,匹配查询到的文档数据中的第一条数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 更新文档,匹配查询到的文档数据中的第一条数据
* @throws Exception
*/
@Test
public void updateFirst() throws Exception {
//更新对象
Person person =new Person();
person.setId(1l);
person.setUserName("张三123");
person.setPassWord("123456");
person.setCreateTime(new Date());
//更新条件
Query query= new Query(Criteria.where("id").is(person.getId()));
//更新值
Update update= new Update().set("userName", person.getUserName()).set("passWord", person.getPassWord());
//更新查询满足条件的文档数据(第一条)
UpdateResult result =mongoTemplate.updateFirst(query,update, Person.class);
if(result!=null){
System.out.println("更新条数:" + result.getMatchedCount());
}
}
}
- 更新文档,匹配查询到的文档数据中的所有数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 更新文档,匹配查询到的文档数据中的所有数据
* @throws Exception
*/
@Test
public void updateMany() throws Exception {
//更新对象
Person person =new Person();
person.setId(1l);
person.setUserName("张三");
person.setPassWord("123456");
person.setCreateTime(new Date());
//更新条件
Query query= new Query(Criteria.where("id").is(person.getId()));
//更新值
Update update= new Update().set("userName", person.getUserName()).set("passWord", person.getPassWord());
//更新查询满足条件的文档数据(全部)
UpdateResult result = mongoTemplate.updateMulti(query, update, Person.class);
if(result!=null){
System.out.println("更新条数:" + result.getMatchedCount());
}
}
}
删除文档
MongoTemplate提供了remove()、findAndRemove()和findAllAndRemove()方法,用于删除文档,示例代码如下:
- 删除符合条件的所有文档
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 删除符合条件的所有文档
* @throws Exception
*/
@Test
public void remove() throws Exception {
Person person =new Person();
person.setId(1l);
person.setUserName("张三");
person.setPassWord("123456");
person.setCreateTime(new Date());
Query query = new Query(Criteria.where("userName").is(person.getUserName()));
DeleteResult result = mongoTemplate.remove(query, Person.class);
System.out.println("删除条数:" + result.getDeletedCount());
}
}
- 删除符合条件的单个文档,并返回删除的文档
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 删除符合条件的单个文档,并返回删除的文档
* @throws Exception
*/
@Test
public void findAndRemove() throws Exception {
Person person =new Person();
person.setId(1l);
person.setUserName("张三");
person.setPassWord("123456");
person.setCreateTime(new Date());
Query query = new Query(Criteria.where("id").is(person.getId()));
Person result = mongoTemplate.findAndRemove(query, Person.class);
System.out.println("删除的文档数据:" + result.toString());
}
}
- 删除符合条件的所有文档,并返回删除的文档
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 删除符合条件的所有文档,并返回删除的文档
* @throws Exception
*/
@Test
public void findAllAndRemove() throws Exception {
Person person =new Person();
person.setId(1l);
person.setUserName("张三");
person.setPassWord("123456");
person.setCreateTime(new Date());
Query query = new Query(Criteria.where("id").is(person.getId()));
List<Person> result = mongoTemplate.findAllAndRemove(query, Person.class);
System.out.println("删除的文档数据:" + result.toString());
}
}
查询文档
MongoTemplate提供了非常多的文档查询方法,日常开发中用的最多的就是find()方法,示例代码如下:
- 查询集合中的全部文档数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 查询集合中的全部文档数据
* @throws Exception
*/
@Test
public void findAll() throws Exception {
List<Person> result = mongoTemplate.findAll(Person.class);
System.out.println("查询结果:" + result.toString());
}
}
查询集合中指定的ID文档数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 查询集合中指定的ID文档数据
* @throws Exception
*/
@Test
public void findById() {
long id = 1l;
Person result = mongoTemplate.findById(id, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
根据条件查询集合中符合条件的文档,返回第一条数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据条件查询集合中符合条件的文档,返回第一条数据
*/
@Test
public void findOne() {
String userName = "张三";
Query query = new Query(Criteria.where("userName").is(userName));
Person result = mongoTemplate.findOne(query, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
根据条件查询集合中符合条件的文档
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据条件查询集合中符合条件的文档
*/
@Test
public void findByCondition() {
String userName = "张三";
Query query = new Query(Criteria.where("userName").is(userName));
List<Person> result = mongoTemplate.find(query, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
根据【AND】关联多个查询条件,查询集合中的文档数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据【AND】关联多个查询条件,查询集合中的文档数据
*/
@Test
public void findByAndCondition() {
// 创建条件
Criteria criteriaUserName = Criteria.where("userName").is("张三");
Criteria criteriaPassWord = Criteria.where("passWord").is("123456");
// 创建条件对象,将上面条件进行 AND 关联
Criteria criteria = new Criteria().andOperator(criteriaUserName, criteriaPassWord);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
List<Person> result = mongoTemplate.find(query, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
根据【OR】关联多个查询条件,查询集合中的文档数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据【OR】关联多个查询条件,查询集合中的文档数据
*/
@Test
public void findByOrCondition() {
// 创建条件
Criteria criteriaUserName = Criteria.where("userName").is("张三");
Criteria criteriaPassWord = Criteria.where("passWord").is("123456");
// 创建条件对象,将上面条件进行 OR 关联
Criteria criteria = new Criteria().orOperator(criteriaUserName, criteriaPassWord);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
List<Person> result = mongoTemplate.find(query, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
根据【IN】关联多个查询条件,查询集合中的文档数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据【IN】关联多个查询条件,查询集合中的文档数据
*/
@Test
public void findByInCondition() {
// 设置查询条件参数
List<Long> ids = Arrays.asList(1l, 10l, 11l);
// 创建条件
Criteria criteria = Criteria.where("id").in(ids);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
List<Person> result = mongoTemplate.find(query, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
根据【逻辑运算符】查询集合中的文档数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据【逻辑运算符】查询集合中的文档数据
*/
@Test
public void findByOperator() {
// 设置查询条件参数
int min = 20;
int max = 35;
Criteria criteria = Criteria.where("age").gt(min).lte(max);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
List<Person> result = mongoTemplate.find(query, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
根据【正则表达式】查询集合中的文档数据
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据【正则表达式】查询集合中的文档数据
*/
@Test
public void findByRegex() {
// 设置查询条件参数
String regex = "^张*";
Criteria criteria = Criteria.where("userName").regex(regex);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
List<Person> result = mongoTemplate.find(query, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
根据条件查询集合中符合条件的文档,获取其文档列表并排序
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据条件查询集合中符合条件的文档,获取其文档列表并排序
*/
@Test
public void findByConditionAndSort() {
String userName = "张三";
Query query = new Query(Criteria.where("userName").is(userName)).with(Sort.by("age"));
List<Person> result = mongoTemplate.find(query, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
根据单个条件查询集合中的文档数据,并按指定字段进行排序与限制指定数目
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 根据单个条件查询集合中的文档数据,并按指定字段进行排序与限制指定数目
*/
@Test
public void findByConditionAndSortLimit() {
String userName = "张三";
//从第一行开始,查询2条数据返回
Query query = new Query(Criteria.where("userName").is(userName)).with(Sort.by("createTime")).limit(2).skip(1);
List<Person> result = mongoTemplate.find(query, Person.class);
System.out.println("查询结果:" + result.toString());
}
}
统计集合中符合【查询条件】的文档【数量】
@RunWith(SpringRunner.class)
@SpringBootTest
public class PersonServiceTest {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 统计集合中符合【查询条件】的文档【数量】
*/
@Test
public void countNumber() {
// 设置查询条件参数
String regex = "^张*";
Criteria criteria = Criteria.where("userName").regex(regex);
// 创建查询对象,然后将条件对象添加到其中
Query query = new Query(criteria);
long count = mongoTemplate.count(query, Person.class);
System.out.println("统计结果:" + count);
}
}
查询指定字段返回
@Test
public void test1() {
Query query = Query.query(Criteria.where("userId").is(1L));
query.fields().include("pid").exclude("_id");
/*Expected to read Document Document{{pid=2031}} into type class java.lang.Integer but didn't find a PersistentEntity for the latter!
* {_id=5fae53927e52992e78a3aecd, pid=2031}
*{_id=5fae53927e52992e78a3aed9, pid=2032}
*{_id=5fae53927e52992e78a3aee5, pid=2033}
* {pid=2033}
* {pid=2034}
* {pid=2035}
*/
List<Object> result = mongoTemplate.find(query, Object.class, "quanzi_publish");
result.forEach(System.out::println);
}
通过query点fields 可以通过 include 指定需要返回的字段。可以链式编程。
exclude排除需要的字段。 因为如果指定需要的字段。不排除_id 的话查询的数据会默认包含_id
{_id=5fae53927e52992e78a3aecd, pid=2031} 所以我这里做了排除。
最后查询的结果是 {pid=2033} 此时我的pid 是一个Long 类型的数据。但是不能用
Long.class 去解析。只能用Object.clss 因为 {pid=2033} 虽然只有一个字段。但是从mongodb查询出来的应该是一个json对象。对象的属性只有一个。没有去看mongodb底层。但应该是做了json的解析。
@Test
public void test2() {
Query query = Query.query(Criteria.where("userId").is(1L));
List<MyLong> result = mongoTemplate.find(query, MyLong.class, "quanzi_publish");
List<Long> pids = result.stream().map(MyLong::getPid).collect(Collectors.toList());
pids.forEach(System.out::println);
}
class MyLong {
private Long pid;
public Long getPid() {
return pid;
}
public void setPid(Long pid) {
this.pid = pid;
}
@Override
public String toString() {
return "MyLong{" +
"pid=" + pid +
'}';
}
}
既然是解析json 。我自己定义了一个类。同样的属性去接。然后用stream 流转为了long类型的list集合。这样做感觉也挺麻烦。但是如果集合字段特别多的话。这样应该能提升一些性能。毕竟如果直接读取整个集合,也是需要遍历。然后提取出id 到一个新集合。步骤差不多。这样只是从mongodb只读取了需要的数据。
查询某字段在MongoDB中是否存在,并返回一条查询记录
String field = "F1_0909";
Query query = new Query();
query.fields().include(field);
query.addCriteria(new Criteria(filed).exists(true));
Map map = mongoTemplate.findOne(query, Map.class, collectionName);
排序
@Test
public void findListStudentSort() {// 排序
Query query = new Query();
query.with(Sort.by(Sort.Direction.DESC, "age"));
List<Student> students = mongoTemplate.find(query, Student.class);
// students】】】" + students);
}
分页
@Test
public void findFenYeList() {// 分页
// 设置分页参数
Query query = new Query();
int currentPage = 2;// 0,1相同
int pageSize = 2;
// 设置分页信息
query.limit(pageSize);
query.skip(pageSize * (currentPage - 1));
// query.addCriteria(Criteria.where("clazzName").regex("天"));
List<Clazz> clazzes = mongoTemplate.find(query, Clazz.class);
// clazzs】】】" + clazzes);
}
@Test
public void findZongHe() {// 分页+范围+模糊查询+排序
// 拼装查询信息
Query query = new Query();
query.addCriteria(Criteria.where("age").gte(6).lte(18));
query.with(Sort.by(Sort.Direction.ASC, "age"));
query.addCriteria(Criteria.where("name").regex("小"));
// 模糊查询名字
Long count = mongoTemplate.count(query, Student.class);
// 查询总记录数
List<Student> list = mongoTemplate.find(query, Student.class);
}
/ 将筛选条件放入管道中
Aggregation aggregation = Aggregation.newAggregation(
lookup,
Aggregation.match(criteria),
Aggregation.group("startSolitaireId") // 分组的字段
.first("startSolitaireId").as("startSolitaireId") // 映射的字段 并取别名
.first("userId").as("userId")
.first("interact").as("interact")
.first("createTime").as("createTime")
.first("startVO").as("startVO"),
Aggregation.sort(Sort.Direction.DESC,"createTime"), // 排序
Aggregation.skip((long) page.getCurrent() * page.getSize()),
Aggregation.limit(page.getSize())); // 分页
MongoDB 聚合操作
聚合表达式
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;
/**
* 聚合表达式 $group
*
* @author mydlq
*/
@Slf4j
@Service
public class AggregateGroupService {
/**
* 设置集合名称
*/
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 使用管道操作符 $group 结合 $count 方法进行聚合统计
*
* @return 聚合结果
*/
public Object aggregationGroupCount() {
// 使用管道操作符 $group 进行分组,然后统计各个组的文档数量
AggregationOperation group = Aggregation.group("age").count().as("numCount");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用管道操作符 $group 结合表达式操作符 $max 进行聚合统计
*
* @return 聚合结果
*/
public Object aggregationGroupMax() {
// 使用管道操作符 $group 进行分组,然后统计各个组文档某字段最大值
AggregationOperation group = Aggregation.group("sex").max("salary").as("salaryMax");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用管道操作符 $group 结合表达式操作符 $min 进行聚合统计
*
* @return 聚合结果
*/
public Object aggregationGroupMin() {
// 使用管道操作符 $group 进行分组,然后统计各个组文档某字段最小值
AggregationOperation group = Aggregation.group("sex").min("salary").as("salaryMin");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用管道操作符 $group 结合表达式操作符 $sum 进行聚合统计
*
* @return 聚合结果
*/
public Object aggregationGroupSum() {
// 使用管道操作符 $group 进行分组,然后统计各个组文档某字段值合计
AggregationOperation group = Aggregation.group("sex").sum("salary").as("salarySum");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用管道操作符 $group 结合表达式操作符 $avg 进行聚合统计
*
* @return 聚合结果
*/
public Object aggregationGroupAvg() {
// 使用管道操作符 $group 进行分组,然后统计各个组文档某字段值平均值
AggregationOperation group = Aggregation.group("sex").avg("salary").as("salaryAvg");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用管道操作符 $group 结合表达式操作符 $first 获取每个组的包含某字段的文档的第一条数据
*
* @return 聚合结果
*/
public Object aggregationGroupFirst() {
// 先对数据进行排序,然后使用管道操作符 $group 进行分组,最后统计各个组文档某字段值第一个值
AggregationOperation sort = Aggregation.sort(Sort.by("salary").ascending());
AggregationOperation group = Aggregation.group("sex").first("salary").as("salaryFirst");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(sort, group);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用管道操作符 $group 结合表达式操作符 $last 获取每个组的包含某字段的文档的最后一条数据
*
* @return 聚合结果
*/
public Object aggregationGroupLast() {
// 先对数据进行排序,然后使用管道操作符 $group 进行分组,最后统计各个组文档某字段值第最后一个值
AggregationOperation sort = Aggregation.sort(Sort.by("salary").ascending());
AggregationOperation group = Aggregation.group("sex").last("salary").as("salaryLast");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(sort, group);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用管道操作符 $group 结合表达式操作符 $push 获取某字段列表
*
* @return 聚合结果
*/
public Object aggregationGroupPush() {
// 先对数据进行排序,然后使用管道操作符 $group 进行分组,然后以数组形式列出某字段的全部值
AggregationOperation push = Aggregation.group("sex").push("salary").as("salaryFirst");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(push);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
}
聚合管道操作符
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;
@Slf4j
@Service
public class AggregatePipelineService {
/**
* 设置集合名称
*/
private static final String COLLECTION_NAME = "users";
@Resource
private MongoTemplate mongoTemplate;
/**
* 使用 $group 和 $match 聚合,先使用 $match 过滤文档,然后再使用 $group 进行分组
*
* @return 聚合结果
*/
public Object aggregateGroupMatch() {
// 设置聚合条件,先使用 $match 过滤岁数大于 25 的用户,然后按性别分组,统计每组用户工资最高值
AggregationOperation match = Aggregation.match(Criteria.where("age").lt(25));
AggregationOperation group = Aggregation.group("sex").max("salary").as("sexSalary");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(match, group);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $sort 聚合,先使用 $group 进行分组,然后再使用 $sort 排序
*
* @return 聚合结果
*/
public Object aggregateGroupSort() {
// 设置聚合条件,按岁数分组,然后统计每组用户工资最大值和用户数,按每组用户工资最大值升序排序
AggregationOperation group = Aggregation.group("age")
.max("salary").as("ageSalary")
.count().as("ageCount");
AggregationOperation sort = Aggregation.sort(Sort.by("ageSalary").ascending());
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group, sort);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $limit 聚合,先使用 $group 进行分组,然后再使用 $limit 限制一定数目文档
*
* @return 聚合结果
*/
public Object aggregateGroupLimit() {
// 设置聚合条件,先按岁数分组,然后求每组用户的工资总数、最大值、最小值、平均值,限制只能显示五条
AggregationOperation group = Aggregation.group("age")
.sum("salary").as("sumSalary")
.max("salary").as("maxSalary")
.min("salary").as("minSalary")
.avg("salary").as("avgSalary");
AggregationOperation limit = Aggregation.limit(5L);
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group, limit);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $skip 聚合,先使用 $group 进行分组,然后再使用 $skip 跳过一定数目文档
*
* @return 聚合结果
*/
public Object aggregateGroupSkip() {
// 设置聚合条件,先按岁数分组,然后求每组用户的工资总数、最大值、最小值、平均值,跳过前 2 条
AggregationOperation group = Aggregation.group("age")
.sum("salary").as("sumSalary")
.max("salary").as("maxSalary")
.min("salary").as("minSalary")
.avg("salary").as("avgSalary");
AggregationOperation limit = Aggregation.skip(2L);
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group, limit);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $project 聚合,先使用 $group 进行分组,然后再使用 $project 限制显示的字段
*
* @return 聚合结果
*/
public Object aggregateGroupProject() {
// 设置聚合条件,按岁数分组,然后求每组用户工资最大值、最小值,然后使用 $project 限制值显示 salaryMax 字段
AggregationOperation group = Aggregation.group("age")
.max("salary").as("maxSalary")
.min("salary").as("minSalary");
AggregationOperation project = Aggregation.project("maxSalary");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(group, project);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
/**
* 使用 $group 和 $unwind 聚合,先使用 $project 进行分组,然后再使用 $unwind 拆分文档中的数组为一条新文档记录
*
* @return 聚合结果
*/
public Object aggregateProjectUnwind() {
// 设置聚合条件,设置显示`name`、`age`、`title`字段,然后将结果中的多条文档按 title 字段进行拆分
AggregationOperation project = Aggregation.project("name", "age", "title");
AggregationOperation unwind = Aggregation.unwind("title");
// 将操作加入到聚合对象中
Aggregation aggregation = Aggregation.newAggregation(project, unwind);
// 执行聚合查询
AggregationResults<Map> results = mongoTemplate.aggregate(aggregation, COLLECTION_NAME, Map.class);
for (Map result : results.getMappedResults()) {
log.info("{}", result);
}
return results.getMappedResults();
}
}
聚合管道操作符
- $project: 可以从文档中选择想要的字段,和不想要的字段(指定的字段可以是来自输入文档或新计算字段的现有字段 ,也可以通过管道表达式进行一些复杂的操作,例如数学操作,日期操作,字符串操作,逻辑操作。
- ** m a t c h : ∗ ∗ 用于过滤数据,只输出符合条件的文档。 match:** 用于过滤数据,只输出符合条件的文档。 match:∗∗用于过滤数据,只输出符合条件的文档。match使用MongoDB的标准查询操作。
- $limit: 用来限制MongoDB聚合管道返回的文档数。
- $skip: 在聚合管道中跳过指定数量的文档,并返回余下的文档。
- $unwind: 将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
- $group: 将集合中的文档分组,可用于统计结果。
- $sort: 将输入文档排序后输出。
关联查询
LookupOperation这个类就是用来进行联表操作的类,具体方法:
- newLookup ,用来创建一个LookupOperation.Builder;
- from, 要连接哪张表,类似Mysql的JOIN;
- localField,主表哪个字段去连接,指明出来;from表参考主表的哪个字段
- foreignField ,form连接的那个表哪个字段关联;
- as, 从表结果集名,最后会在主表多出这个自定义列,默认List;理解为as一个别名,会把从表的数据以数组的形式在as字段内
表结构
Item
{
"_id": "111",
"sActiveId": "222",
"sName": "333",
"sIcon": "444",
"sDes": "555",
"iItemType": NumberInt("1"),
"sValue": "666",
"iProperty": [
"0"
],
"iDuration": NumberInt("77"),
"createTime": ISODate("2022-03-23T08:13:19.694Z"),
"updateTime": ISODate("2022-03-23T08:13:19.694Z"),
"iStatus": NumberInt("0")
}
ItemUser
{
"_id": "222",
"sActiveId": "333",
"sItemId": "111",
"sUserId": "444",
"iCount": NumberInt("4")
}
生成管道,以下是ItemUser 是主表****Item是从表
// 联表
LookupOperation lookupOperation = LookupOperation.newLookup()
// 连接哪张表
.from("Item")
// 主表哪个字段连接
.localField("sItemId")
// 从表哪个字段关联
.foreignField("_id")
// 从表结果集名 最后会在主表多出这个自定义列 默认List
.as("item");
// 查询(只能是主表的字段,取别名字段不可以,例如:item.sName 是不可以的)
Criteria criteria = Criteria.where("sUserId").is("444");
// 类似mysql的select列 如果要用从表的列 就as自定义列名点属性
ProjectionOperation projectionOperation = Aggregation.project("id", "sItemId", "iCount", "item.iDuration", "item.sName", "item.sIcon", "item.sDes", "item.iItemType");
// 建立管道
Aggregation aggregation = Aggregation.newAggregation(
// 联表
lookupOperation,
// 查询
Aggregation.match(criteria),
// 将某个集合列拆成字段添加主表
Aggregation.unwind("item"),
// 排序
Aggregation.sort(Sort.Direction.DESC, "createTime"),
// select
projectionOperation
);
AggregationResults<JSONObject> aggregationResults = mongoTemplate.aggregate(aggregation, "ItemUser", JSONObject.class);
List<JSONObject> result = aggregationResults.getMappedResults();
前面提到,as会在主表新增个列,列里内容是数组,Aggregation.unwind(“item”)的作用就是把as列里数组拆掉,通过ProjectionOperation 加在主表自定义字段中
实际的联查写法
//多表关联的条件声明
LookupOperation cusAndInfoLookup = LookupOperation.newLookup().
from("adrs").//1.副表表名字
localField("_id").//2.主表的关联字段
foreignField("adrsId").//3.副表的关联字段
as("adrs");//4.建议和1一致,结果的别名
//关联多张表就写多个
// LookupOperation cusAndInfoLookup1 = LookupOperation.newLookup().
// from("adrs").
// localField("_id").
// foreignField("adrsId").
// as("adrs");
//多表的关联条件,查询条件均传入到此
Aggregation aggregation = Aggregation.newAggregation(
cusAndInfoLookup,
// cusAndInfoLookup1,
// Aggregation.match(Criteria.where("_id").lte(2)),
//5.此作用处下文解释
// Aggregation.unwind("adrs"),
//筛选条件,筛选主表的字段直接写,副表则是'别名.字段名'
Aggregation.match(Criteria.where("adrs.adrsId").is(1))
);
//5.此处填写主表名称
AggregationResults<JSONObject> results = mongoTemplate.aggregate(aggregation, "tab_map", JSONObject.class);
List<JSONObject> objectList = results.getMappedResults();
for (JSONObject json : objectList) {
System.out.println(json);
}
unwind的作用,默认关联查询出现多个关联值时,结果会以array返回,例如一个用户有多个收货地址,则会返回
{"id":"1","adrs":[{adrs1},{adrs2}]}
unwind("adrs")返回数据成为常见的sql返回多条
{"id":"1","adrs":{adrs1}}
{"id":"1","adrs":{adrs2}}
分组,两表三表联查
####分组,两表三表联查###########################################################
import com.csw.mongodbspringbootdemo.entity.Chair;
import com.csw.mongodbspringbootdemo.entity.Desk;
import com.csw.mongodbspringbootdemo.entity.Room;
import com.mongodb.BasicDBObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.LookupOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SpringBootTest
@RunWith(SpringRunner.class)
public class RoomDeskRecommend {
@Autowired
private MongoTemplate mongoTemplate;
@Test
public void saveRoom() {// 添加房间
Room room = new Room();
room.setName("空房间2");
room.setUnitCode(UUID.randomUUID().toString());
mongoTemplate.save(room);
Room room2 = new Room();
room2.setName("空房间1");
room2.setUnitCode(UUID.randomUUID().toString());
mongoTemplate.save(room2);
}
@Test
public void saveDesk() {// 添加桌子
String roomName = "光明房间";
String deskName = "5号桌子";
Query query = new Query(Criteria.where("name").is(roomName));
Room room = mongoTemplate.findOne(query, Room.class);
Desk desk = new Desk();
desk.setName(deskName);
assert room != null;
desk.setUnitCode(room.getUnitCode());
mongoTemplate.save(desk);
System.out.println(room);
Query query2 = new Query(Criteria.where("name").is(deskName));
Desk desk2 = mongoTemplate.findOne(query2, Desk.class);
System.out.println(desk2);
}
@Test
public void groupBy() {// group
List<AggregationOperation> aggs = new ArrayList<>();
// aggs.add(Aggregation.match(Criteria.where("name").is("log")));
aggs.add(Aggregation.group("name").count().as("count"));
aggs.add(Aggregation.project().and("_id").as("name").and("count").as("count"));
Aggregation agg = Aggregation.newAggregation(aggs);
AggregationResults<Map> results = mongoTemplate.aggregate(agg, Desk.class, Map.class);
for (Map result : results) {
System.out.println(result);
}
}
@Test
public void findMoreTable() {// 两表联查
LookupOperation lookupOperation = LookupOperation.newLookup()
.from("room"). // 关联表名
localField("unitCode"). // 主关联字段
foreignField("unitCode").// 从表关联字段对应的次表字段
as("rooms");// 查询结果集合名
Criteria ordercri = Criteria.where("rooms").not().size(0);// 只查询有宠物的人
// ordercri.and("age").gte(1).lte(5);//只查询1岁到5岁的宠物
AggregationOperation matchZi = Aggregation.match(ordercri);
Aggregation aggregation = Aggregation.newAggregation(lookupOperation, matchZi);// 排序
List<Map> results = mongoTemplate.aggregate(aggregation, "desk", Map.class).getMappedResults(); // 查询出的结果集为BasicDBObject类型
for (Map result : results) {
System.out.println(result);
}
}
@Test
public void findMoreTable2() {// 两表联查
LookupOperation lookupOperation = LookupOperation.newLookup().from("desk"). // 关联表名
localField("unitCode"). // 主关联字段
foreignField("unitCode").// 从表关联字段对应的次表字段
as("desks");// 查询结果集合名
Criteria ordercri = Criteria.where("desks").not().size(0);// 只查询有宠物的人
// ordercri.and("age").gte(1).lte(5);//只查询1岁到5岁的宠物
AggregationOperation matchZi = Aggregation.match(ordercri);
Aggregation aggregation = Aggregation.newAggregation(lookupOperation, matchZi);// 排序
List<Map> results = mongoTemplate.aggregate(aggregation, "room", Map.class).getMappedResults(); // 查询出的结果集为BasicDBObject类型
for (Map result : results) {
System.out.println(result);
}
}
@Test
public void findMoreTableZongHe() {// 两表联查
int pageNumber = 2;// 0,1相同
int pageSize = 2;
// 拼装关联信息
LookupOperation lookupOperation = LookupOperation.newLookup().from("room"). // 关联表名
localField("unitCode"). // 主关联字段
foreignField("unitCode").// 从表关联字段对应的次表字段
as("ClazzStudents");// 查询结果集合名
// 拼装具体查询信息
// 次表
Criteria ordercri = Criteria.where("ClazzStudents").not().size(0);// 只查询有宠物的人
// ordercri.and("age").gte(1).lte(5);//只查询1岁到5岁的宠物
AggregationOperation matchZi = Aggregation.match(ordercri);
// 主表
Criteria qqq = Criteria.where("name").regex("号");// 只查询名字中带有文的人
AggregationOperation matchFu = Aggregation.match(qqq);
// 分页查询
Aggregation aggregation = Aggregation.newAggregation(matchFu, lookupOperation, matchZi,
Aggregation.sort(Sort.Direction.DESC, "name"),
Aggregation.skip(pageSize > 1 ? (pageNumber - 1) * pageSize : 0), Aggregation.limit(pageSize));// 排序
// Aggregation.skip(pageable.getPageNumber()>1?(pageable.getPageNumber()-1)*pageable.getPageSize():0),//pagenumber
// 分页
/*
* Aggregation.skip(pageSize>1?(pageNumber-1)*pageSize:0);
* Aggregation.limit(pageSize);
*/
// Aggregation.group("name");
// 总数查询
Aggregation counts = Aggregation.newAggregation(matchFu, lookupOperation, matchZi);
int count = mongoTemplate.aggregate(counts, Desk.class, BasicDBObject.class).getMappedResults().size();
System.out.println("【count】" + count);
List<Map> results = mongoTemplate.aggregate(aggregation, "desk", Map.class).getMappedResults(); // 查询出的结果集为BasicDBObject类型
for (Map result : results) {
System.out.println(result);
}
}
@Test
public void saveChair() {// 添加椅子
String roomName = "光明房间";
String chairName = "1号椅子";
Query query = new Query(Criteria.where("name").is(roomName));
Room room = mongoTemplate.findOne(query, Room.class);
Chair chair = new Chair();
chair.setName(chairName);
assert room != null;
chair.setUnitCode(room.getUnitCode());
mongoTemplate.save(chair);
}
@Test
public void findMoreTable3_0() {// 三表联查测试,第一个表关联第二个人表(关联字段1),第一个表关联第三个表(关联字段1)
LookupOperation lookupOperation = LookupOperation.newLookup().from("desk"). // 关联表名
localField("unitCode"). // 主关联字段
foreignField("unitCode").// 从表关联字段对应的次表字段
as("desks");// 查询结果集合名
Criteria ordercri = Criteria.where("desks").not().size(0);// 只查询有宠物的人
// ordercri.and("age").gte(1).lte(5);//只查询1岁到5岁的宠物
AggregationOperation matchZi = Aggregation.match(ordercri);
LookupOperation lookupOperation2 = LookupOperation.newLookup().from("chair"). // 关联表名
localField("unitCode"). // 主关联字段
foreignField("unitCode").// 从表关联字段对应的次表字段
as("chairs");// 查询结果集合名
Criteria ordercri2 = Criteria.where("chairs").not().size(0);// 只查询有宠物的人
// ordercri.and("age").gte(1).lte(5);//只查询1岁到5岁的宠物
AggregationOperation matchZi2 = Aggregation.match(ordercri2);
Aggregation aggregation = Aggregation.newAggregation(lookupOperation, matchZi, lookupOperation2, matchZi2);// 排序
List<Map> results = mongoTemplate.aggregate(aggregation, "room", Map.class).getMappedResults(); // 查询出的结果集为BasicDBObject类型
for (Map result : results) {
System.out.println(result);
}
}
// 数据模拟
@Test
public void findMoreTable3_1() {// 三表联查测试,第一个表关联第二个人表(关联字段1),第一个表关联第三个表(关联字段2)
LookupOperation lookupOperation = LookupOperation.newLookup().from("desk"). // 关联表名
localField("unitCode"). // 主关联字段
foreignField("unitCode").// 从表关联字段对应的次表字段
as("desks");// 查询结果集合名
Criteria ordercri = Criteria.where("desks").not().size(0);// 只查询有宠物的人
// ordercri.and("age").gte(1).lte(5);//只查询1岁到5岁的宠物
AggregationOperation matchZi = Aggregation.match(ordercri);
LookupOperation lookupOperation2 = LookupOperation.newLookup().from("chair"). // 关联表名
localField("lastCode"). // 主关联字段
foreignField("lastCode").// 从表关联字段对应的次表字段
as("chairs");// 查询结果集合名
Criteria ordercri2 = Criteria.where("chairs").not().size(0);// 只查询有宠物的人
// ordercri.and("age").gte(1).lte(5);//只查询1岁到5岁的宠物
AggregationOperation matchZi2 = Aggregation.match(ordercri2);
Aggregation aggregation = Aggregation.newAggregation(lookupOperation, matchZi, lookupOperation2, matchZi2);// 排序
List<Map> results = mongoTemplate.aggregate(aggregation, "room", Map.class).getMappedResults(); // 查询出的结果集为BasicDBObject类型
for (Map result : results) {
System.out.println(result);
}
}
// 数据模拟
@Test
public void findMoreTable3_3() {// 三表联查测试,第一个表关联第二个人表(关联字段1),第二个表关联第三个表(关联字段2)
LookupOperation lookupOperation = LookupOperation.newLookup().from("room"). // 关联表名
localField("unitCode"). // 主关联字段
foreignField("unitCode").// 从表关联字段对应的次表字段
as("rooms");// 查询结果集合名
Criteria ordercri = Criteria.where("rooms").not().size(0);// 只查询有宠物的人
// ordercri.and("age").gte(1).lte(5);//只查询1岁到5岁的宠物
AggregationOperation matchZi = Aggregation.match(ordercri);
LookupOperation lookupOperation2 = LookupOperation.newLookup().from("chair"). // 关联表名
localField("rooms.lastCode"). // 主关联字段
foreignField("lastCode").// 从表关联字段对应的次表字段
as("chairs");// 查询结果集合名
Criteria ordercri2 = Criteria.where("chairs").not().size(0);// 只查询有宠物的人
// ordercri.and("age").gte(1).lte(5);//只查询1岁到5岁的宠物
AggregationOperation matchZi2 = Aggregation.match(ordercri2);
Aggregation aggregation = Aggregation.newAggregation(lookupOperation, matchZi, lookupOperation2, matchZi2);// 排序
List<Map> results = mongoTemplate.aggregate(aggregation, "desk", Map.class).getMappedResults(); // 查询出的结果集为BasicDBObject类型
for (Map result : results) {
System.out.println(result);
}
}
常用函数
使用前我们先来了解一下常用的函数
- Aggregation.group() : 聚合函数,将某个字段或者某个数组作为分组统计的依据,在group的基础上又扩展出以下函数:
- sum() : 求和
- max() : 获取最大值
- min() : 获取最小值
- avg() : 获取平均值
- count() : 统计条目数
- first () : 获取group by 后的某个字段的首个值
- last() : 获取 group by 后的某个字段的最后一个值
- push() : 在结果文档中插入值到一个数组中
- addToSet() : 在结果文档中插入值到一个数组中,但不创建副本(作为集合)。
- Aggregation.match() : 过滤函数,主要存储过滤数据的条件,输出符合条件的记录
- Aggregation.project(): 修改数据结构函数,将前面管道中的获取的字段进行重名,增加,修改字段等操作。
- Aggregation.unwind():将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。当preserveNullAndEmptyArrays为true时,将包括字段为null,空,或者缺失的数据;
- Aggregation.sort(): 排序函数,将上级管道的内容按照某个字段进行排序并且输出。值为1升、-1降。sort一般放在group后,也就是说得到结果后再排序,如果先排序再分组没什么意义;
- Aggregation.limit(): 限制输出函数,将聚合返回的内容限定在某个条目之内。通常作为页面大小
- Aggregation.skip(): 跳过指定数量的条目再开始返回数据的函数,通常和sort(),limit()配合,实现数据翻页查询等操作。
- Aggregation.lookup(): 连表查询,将被关联集合添加到执行操作的集合中。
实例
用accountId和status做group操作
Copymongodb:
db.getCollection('mro_fn_subscribes').aggregate([
{
$group:{
"_id":{"_id":"$accountId", "status": "$status" },
"count":{"$sum": NumberInt(1)},
"statusSum":{"$sum": "$status"},
"codeAvg":{"$avg":"$fnCode"},
"codeMax":{"$max":"$fnCode"},
"codeMin":{"$min":"$fnCode"},
"codeFirst":{"$first":"$fnCode"},
"codeLast":{"$last":"$fnCode"},
}
}
])
java:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.group("accountId", "status")
.count().as("count")
.sum("status").as("statusSum")
.avg("fnCode").as("codeAvg")
.max("fnCode").as("codeMax")
.min("fnCode").as("codeMin")
.first("fnCode").as("codeFirst")
.last("fnCode").as("codeLast")
);
match管道过滤:
Copymongodb:
db.getCollection('mro_fn_subscribes').aggregate(
{$match:{userId:"a"}}
)
java:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(new Criteria().and("userId").is("a")
);
project筛选字段:
Copymongo:
db.getCollection('mro_fn_subscribes').aggregate([
{
"$group" : {
"_id" : "$_id",
"num" : {
"$sum" : "$num"
},
"firstName" : {
"$first" : "$name"
},
"lastName" : {
"$last" : "$name"
}
}
},
{
"$project" : {
"_id" : 1,
"num" : 1,
"firstName" : 1,
"name" : "$lastName"
}
}
])
java:
// 初始化聚合
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.group(new String[] {"_id"}).sum("num").as("num")
.first("name").as("firstName")
.last("name").as("lastName"),
Aggregation.project("_id", "num", "firstName")
.and("lastName").as("name") // 重新命名字段
);
unwind拆分数组
Copymongo:
db.col.aggregate(
{
$match:{userid:"a"}
},
{
$unwind:{
path:"$items", includeArrayIndex: "arrayIndex"
}
}
)
java:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(new Criteria().and("userId").is("a"),
Aggregation.unwind("items",true)
);
sort skip limit处理数据:
CopyMongo:
db.getCollection('mro_fn_subscribes').aggregate([
{
"$group" : {
_id:{"_id":"$accountId", "status": "$status" }
}
},
{
"$sort" : {
"num" : -1
}
},
{
"$skip" : NumberInt(10)
},
{
"$limit" : NumberInt(2)
}
]
)
Java:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.group("accountId", "status")
Aggregation.sort(Direction.DESC, "num"), //将num降序
Aggregation.skip(10), //从第10条记录开始
Aggregation.limit(2) //取两条数据
);
lookup多表关联查询:
Copy# Mongo:
db.getCollection('mro_accounts').aggregate([
{
$lookup: {
from:"mro_profiles", # 被关联表名
localField:"userName", # 主表(mro_accounts)中用于关联的字段
foreignField:"mobile", # 被关联表(mro_profiles)中用于关联的字段
as:"profileDoc" # 被关联的表的别名
}
}
])
# Java
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.lookup("mro_profiles", "userName", "mobile", "profileDoc") //分别对应from, localField, foreignField, as
);
获取查询结果
在创建好Aggregation对象之后,再用 mongotemplate.aggregate(aggregation, “mro_fn_subscribes”, Fnsubscribe.class).getMappedResults() 获取查询的对象列表
日期字符串转ISO日期格式mogodb
public static void main(String[] args) {
ZoneId zone = ZoneId.systemDefault();
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime birthDate = LocalDateTime.parse("2022-03-11" + " 00:00:00", df);
Instant instant = birthDate.atZone(zone).toInstant();
Date date = Date.from(instant);
System.out.println("birthDate: " + birthDate);
System.out.println("instant: " + instant);
System.out.println("date: " + date);
}
支持 $filter 数组聚合运算符
Java Spring Data MongoDB是用于与MongoDB数据库进行交互的框架,提供了许多功能强大的 API 和管理工具,其中包含了大量数据操作函数,包括数组聚合运算符,$filter也是其中一种。
在MongoDB中,当需要使用聚合函数过滤数组中的元素时,可以使用$filter运算符。具体使用方法如下:
{
$project: {
filteredArray: {
$filter: {
input: "$array",
as: "element",
cond: { $gt: ["$$element", 5] }
}
}
}
}
上述代码将会筛选数组中所有大于5的元素并返回一个新的数组。
在Java Spring Data MongoDB中,$filter运算符同样被支持。可以使用AggregationOperation来拼接查询条件。具体实现代码如下:
AggregationOperation filter = Aggregation.project()
.andFilter(ArrayOperators.Filter
.filter("array")
.as("element")
.by(ComparisonOperators.Gt.valueOf("$$element").greaterThan(5)))
.as("filteredArray");
在上述代码中,使用了ArrayOperators.Filter
来表示$filter运算符,并使用ComparisonOperators.Gt
来表示’>'符号,从而实现了对数组中元素进行筛选。
需要注意的是, f i l t e r 操作符只适用于聚合操作中,即使用聚合函数进行筛选。如果想要在数据操作中对数组中的元素进行筛选,则需要使用 filter操作符只适用于聚合操作中,即使用聚合函数进行筛选。如果想要在数据操作中对数组中的元素进行筛选,则需要使用 filter操作符只适用于聚合操作中,即使用聚合函数进行筛选。如果想要在数据操作中对数组中的元素进行筛选,则需要使用elemMatch操作符来实现。具体操作方法可参考以下代码:
Criteria criteria = Criteria.where("array").elemMatch(
Criteria.where("$gt").gt(5));
Query query = new Query(criteria);
List<DBObject> results = mongoTemplate.find(query, DBObject.class,"collectionName");
上述代码使用$elemMatch操作符来筛选数组中所有大于5的元素,并使用mongoTemplate.find
方法来获取符合条件的数据项。
扩展的相关知识点也非常广泛,如MongoDB聚合函数的使用、Java Spring Data MongoDB的API使用、MongoDB数据库的操作等。在实际应用过程中,需要注意的是,在使用聚合函数进行操作时,应尽量避免数据过多而导致的性能,可以采用分批次操作的方法来进行优化。同时,需要根据实际情况来选择 e l e m M a t c h 或者 elemMatch或者 elemMatch或者filter操作符,以及其他更合适的操作函数来实现查询需求。
参考
1、菜鸟教程 - mongodb
2、超级小豆丁 - MongoDB 介绍
3、MongoDB 文档查询 api 介绍