从String到ObjectId的Spring数据MongoDb聚合查找
Posted
技术标签:
【中文标题】从String到ObjectId的Spring数据MongoDb聚合查找【英文标题】:Spring data MongoDb Aggregation lookup from String to ObjectId 【发布时间】:2020-09-09 19:05:50 【问题描述】:我正在使用 Spring (boot) data 2.2.7 和 mongodb 4.0。 我已经设置了 3 个我试图通过聚合查找操作加入的集合。
目录 库存 操作目录
"_id" : ObjectId("5ec7856eb9eb171b72f721af"),
"model" : "HX711",
"type" : "DIGITAL",
....
映射者
@Document(collection = "catalog")
public class Product implements Serializable
@Id
private String _id;
@TextIndexed
private String model;
....
库存
"_id" : ObjectId("5ec78573b9eb171b72f721ba"),
"serialNumber" : "7af646bb-a5a8-4b86-b56b-07c12a625265",
"bareCode" : "72193.67751691974",
"productId" : "5ec7856eb9eb171b72f721af",
......
映射者
@Document(collection = "stock")
public class Component implements Serializable
@Id
private String _id;
private String productId;
....
productId 字段指的是目录集合中的 _id
运营
"_id" : ObjectId("5ec78671b9eb171b72f721d3"),
"componentId" : ""5ec78573b9eb171b72f721ba",
.....
映射者
public class Node implements Serializable
@Id
private String _id;
private String componentId;
....
componentId 字段是指股票集合中的 _id 字段
我想查询 operations 或 stock 集合以检索按 Product.model 字段排序的相应 Node 或 Component 对象列表(在 catalog强>集合。)
虽然目标是用 Java 编写代码,但我尝试先在 Mongo shell 中发出请求,但在尝试加入时我什至无法正常工作(查找)带有 ObjectId 的字符串:Node.componentId -> Component._id Component.productId -> Product._id
对于关系 Component(stock) -> Product(Catalog) 我试过了
LookupOperation lookupOperation = LookupOperation.newLookup()
.from("catalog")
.localField("productId")
.foreignField("_id")
.as("product");
TypedAggregation<Component> agg =
Aggregation.newAggregation(
Component.class,
lookupOperation
);
AggregationResults<Component> results = mongoTemplate.aggregate(agg, "stock", Component.class);
return results.getMappedResults();
但它会返回没有产品信息的整个组件记录。
["_id":"5ec78573b9eb171b72f721b0","uuId":"da8800d0-b0af-4886-80d1-c384596d2261","serialNumber":"706d93ef-abf5-4f08-9cbd-e7be0af1681c","bareCode":"90168.94737714577","productId":"5ec7856eb9eb171b72f721a9","created":"2020-05-22T07:55:31.66","updated":null, .....]
感谢您的帮助。
注意: 除了@Valijon 回答能够按预期获得结果之外,返回的对象必须包含“产品”属性,否则不会返回任何内容(例如使用 JSON REST 服务)
public class ComponentExpanded implements Serializable
private String product;
....
与
AggregationResults<ComponentExpanded> results =
mongoTemplate.aggregate(agg,mongoTemplate.getCollectionName(Component.class), ComponentExpanded.class);
【问题讨论】:
【参考方案1】:如您所见,问题在于productId
和_id
之间的类型不匹配。
要加入这样的数据,我们需要执行uncorrelated sub-queries,并不是每个“新”功能都会立即进入抽象层,例如spring-mongo
。
试试这个:
Aggregation agg = Aggregation.newAggregation(l -> new Document("$lookup",
new Document("from", mongoTemplate.getCollectionName(Product.class))
.append("let", new Document("productId", new Document("$toObjectId", "$productId")))
.append("pipeline",
Arrays.asList(new Document("$match",
new Document("$expr",
new Document("$eq", Arrays.asList("$_id", "$$productId"))))))
.append("as", "product")),
Aggregation.unwind("product", Boolean.TRUE));
AggregationResults<Component> results = mongoTemplate.aggregate(agg,
mongoTemplate.getCollectionName(Component.class), Component.class);
return results.getMappedResults();
MongoPlayground 在这里查看 shell 查询的样子。
注意:对于Java v1.7
,您需要实现AggregationOperation
,如下所示:
AggregationOperation l = new AggregationOperation()
@Override
public Document toDocument(AggregationOperationContext context)
return new Document(...); // put here $lookup stage
;
【讨论】:
了解,您使用管道创建了一个基于 Bson 文档的查找操作,该操作使用从原始字段转换为 ObjectId 的内部字段。我是否正确建议不需要像在我的模型中那样展开操作,因为它是一对一的关系?我已经更新了问题(@see note),我是否也提供了一个不同的对象来返回结果。无论如何,您的解决方案都有效。非常感谢 @Emmanuel 好吧,当您执行$lookup
时,它执行 left outer join
并创建具有 0...n
基数的 array
字段。在您的情况下,它可能总是包含 1 个项目的数组,这就是为什么我添加了额外的 $unwind
运算符以将数组展平为单个字段。您可以将 MongoDB 尝试将 BSON 文档转换为您的类的任何兼容类设置为输出类。不客气。
您是否对编码级联查找操作以扁平化 Node.componentUuId -> Component.productUuId -> Product.uuId 有任何想法。我的意思是获得一个填充的节点结果文档,其中嵌入了它的组件和产品?我在 mongo shell 中得到它,然后根据所需的结构设计了一个类,但我面临一个不可预测的空指针异常......没有调试能力。 notive :由于我没有时间实施您的解决方案来解决字符串-> objectId 转换,因此我正在使用我的内部对象 uuids 关系。我稍后会实施它。再次感谢^^
@Emmanuel 请提供示例。如果我理解正确,在不相关的子查询中,您可以执行另一个$lookup
,依此类推...发布Node
和Component
的相关性,以便我可以检查您需要如何构建查询。
@Valijon 这个答案真的很有帮助以上是关于从String到ObjectId的Spring数据MongoDb聚合查找的主要内容,如果未能解决你的问题,请参考以下文章
如何使用弹簧数据将 BigInteger 转换为 Objectid
如何使用 Spring Data MongoDB 通过 GridFS ObjectId 获取二进制流
在 C# 中从序列化为 JSON 的 mongodb 文档中删除 ObjectId
如何使用 Spring Boot 和 MongoDB 从 JSON 列表中删除对象