先补充一个数据结构
@Data
public class Answer {
private String id;
private String subjectId;
private String topicId;
private String topicValue;
private String regOper;
查询语句也有小改动
db.subject.aggregate([
{$match:{_id:{$eq:ObjectId('5f363791badd872947095089')}}},
{$addFields:{id:{ $toString: '$_id' }}},
$lookup:
from: "topic",
localField: "id",
foreignField: "subjectId",
as: "topics"
{$unwind:"$topics"},
{$addFields:{'topics.id':{ $toString: '$topics._id' }}},
$lookup:
from: "answer",
localField: "topics.id",
foreignField: "topicId",
as: "topics.answer"
java代码
MongoCollection<Document> collection= mongoOps.getCollection("subject");
List<Document> results= new ArrayList<>();
collection.aggregate(
Arrays.asList(
Aggregates.match(Filters.eq("_id", new ObjectId(subjectId))),
Aggregates.addFields(new Field<>("id",new Document("$toString","$_id"))),
Aggregates.lookup("topic","id","subjectId","topics"),
Aggregates.unwind("$topics"),
Aggregates.addFields(new Field<>("topics.id",new Document("$toString","$topics._id"))),
Aggregates.lookup("answer","topics.id","topicId","topics.answer"),
Aggregates.group("$_id",Accumulators.first("title","$title"),
Accumulators.push("topics","$topics"))
).forEach( t -> results.add(t));
使用原生的API时,如果通过自动生成的_id
去查询,记得使用数据类型ObjectId
,使用mongoTemplate应该是会自动进行转换
相较于SQL中的left join,感觉mongo的lookup要多写出来很多代码,特别是多层嵌套时更是感觉不便;但是相对的,mongo的语法更加的结构化,通过pipeline将所有的步骤穿在一起,在编写代码时感觉也更加整洁。同时也提醒大家,在设计数据结构时,关联字段类型一定要一致,特别是ObjectId
和String,在java代码层面感受不到区别,但是在实际落表后确是完完全全不同,由此在处理时也会带来一系列的不便
最后附上代码地址https://gitee.com/xiiiao/mongo-learning
第三篇笔记本想着记录一些简单的增删改查,由于中间很久没有写就一时懒得整理了,先把最近刚遇到的问题记录一下通过Aggregation和lookup进行多级关联查询在SQL中可以通过left join操作进行多表的关联查询,在mongo中,类似的操作为Aggregation中的lookup,可以看一下如下数据结构@Datapublic class Subject { private ObjectId id; private String name; private String
这两天做mongodb的多表且多字段关联查询,这里做下使用记录,后续可套用该模式使用。
如果不考虑性能影响的话,可以无限使用 lookup 做多表关联。
多表关联查询的效率比单表加循环查询效率非常高。
let mongoUrl=`mongodb://root:pwd@127.0.0.1:27017/dbName`;//数据库连接
let mongo=require("lycq").mongo;
async function main(){
console.log("启动")
let db.
from: <collection to join>,
localField: <field from the input documents>,
foreignField: <field from the documents of the "from" collection>,
as: <output array field>
Mongodb 3.2版本新增,主要用来实现多表关联查询, 相当关系型数据库中多表关联查询。
每个输入待处理的文档,经过$lookup 阶段的处理,输出的新文档中会包含一个新生成的数组(可根据需要命名新key )。数组列存放的数据是来自被Join集合的适配文档,如果没有,集合为空(即 为[ ])
二、$lookup的语法
$lookup的语法
db.collection.aggregate([
mongostat是mongdb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取mongodb的当前运行状态,并输出。如果你发现数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。它的输出有以下几列:类似于MySQL的slowlog,MongoDB可以监控所有慢的以及不慢的查询。Profiler默认是关闭的,你可以选择全部开启,或者有慢查询的时候开启。查看Profile日志3个字段的意义不多说,此处有官方文档。注意,造成满查询可能是索引的问题,也可能是数据不在内存造成因此磁盘读入造成。Mongodb自带了Web控制台,默认和数据服务一同开
参数说明:sql(Operators)
where ($match) 、group by ($group) 、having($match)、select($project)、order by($sort)、limit($limit)
sum($sum)、count($sum)、join($lookup)
MongoVUE操作:
Aggregation agg = Aggregation.newAggregation(
Aggregation.lookup("表2", "表1字段", "表2字段", "alias"),
Aggregation.sort(Sort.Direction.DESC, "alias.表2字段")
List<结果类型> results = mongoTemplate.aggregate(agg, "表1", 结果类型.class).getMappedResults();
在上面的代码中,我们首先使用lookup操作符将两个表连接起来。然后使用sort操作符按照表2字段倒序排序结果。通过将alias参数指定为结果集的别名,我们可以在管道中对连表查询结果进行引用。
如果你在尝试使用此查询时遇到出现倒序异常(排序结果不正确),可以考虑使用索引来提高查询性能。此外,也可以尝试手动编写聚合管道的JSON字符串来实现联表查询操作,这样可以更加直观地了解查询的实际运作方式。