我在Debian Stretch(9.12)上使用 mongoDB 4.0的 Spring (引导)2.2.7。 我已经设置了3个集合,这些集合正试图通过聚合查找级联操作加入。
每个类都有一个将它们链接在一起的uuid字符串属性。
节点(传感器,接收器,基站等)
@Document(collection = "operations")
public class Node implements Serializable {
@Id
private String _id;
private String componentUuId;
....
}
组件(带有序列号,裸代码的交付产品)
@Document(collection = "stock")
public class Component implements Serializable {
@Id
private String _id;
private String uuId;
private String productUuId;
....
}
产品(一种市场人工制品)
@Document(collection = "catalog")
public class Product implements Serializable {
@Id
private String _id;
private String uuId;
....
}
在mongo shell中运行此命令时:
db.operations.aggregate([
{
$lookup: {
"from": "stock",
"localField": "componentUuId",
"foreignField": "uuId",
"as": "component"
}
},
{
$lookup: {
"from": "catalog",
"localField": "component.productUuId",
"foreignField": "uuId",
"as": "product"
}
}
]).pretty()
我明白了
{
"_id" : ObjectId("5ec952a7714e7e248b5fb98b"),
"uuId" : "3b5e3417-166c-4d69-9fa5-b0856d819541",
"componentUuId" : "57eff5c5-8b3c-43cb-9f2d-1c4098fc0c1f",
"component" : [
{
"_id" : ObjectId("5ec952a4714e7e248b5fb97f"),
"uuId" : "57eff5c5-8b3c-43cb-9f2d-1c4098fc0c1f",
"productUuId" : "3da7a6a6-ccf6-4fe1-892a-a6d6b82396c1",
"created" : ISODate("2020-05-23T14:43:16.588Z"),
"_class" : "org.open_si.udc_common.models.Component"
.......
}
],
"product" : [
{
"_id" : ObjectId("5ec952a1714e7e248b5fb969"),
"uuId" : "3da7a6a6-ccf6-4fe1-892a-a6d6b82396c1",
"model" : "TMP36GT9Z",
"_class" : "org.open_si.udc_common.models.Product"
......
}
]
}
所以要在我运行的Java(带有Spring-data-mongodb)中达到相同的目标
Aggregation agg = Aggregation.newAggregation(
Aggregation.lookup(mongoTemplate.getCollectionName(Component.class),
"componentUuId", "uuId", "component"),
Aggregation.lookup(mongoTemplate.getCollectionName(Product.class),
"component.productUuId", "uuId", "product")
);
AggregationResults<NodeExpanded> results = mongoTemplate.aggregate(agg, mongoTemplate.getCollectionName(Node.class), NodeExpanded.class);
return results.getMappedResults();
使用NodeExpanded类
public class NodeExpanded implements Serializable {
private String uuId;
private Component component;
private Product product;
....
}
注释:我不会扩展Node基类,因为在出现以下问题之前,我得到了重复的键错误。
问题是我在托管该代码的服务中遇到错误:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
不幸的是,我不知道如何在Spring的较低级别进行调试,也无法找出原始错误是什么。
请注意,下面的代码可以获取链接到 Component 的产品:
Aggregation agg = Aggregation.newAggregation(
Aggregation.lookup(mongoTemplate.getCollectionName(Product.class),
"productUuId", "uuId", "product")
);
AggregationResults<ComponentExpanded> results =
mongoTemplate.aggregate(agg,mongoTemplate.getCollectionName(Component.class), ComponentExpanded.class);
return results.getMappedResults();
具有扩展的类:
public class ComponentExpanded implements Serializable {
private String uuId;
private Product product;
...
}
有什么主意吗?预先感谢。
编辑
为了更深入地调试,我将代码限制为仅将 operations 集合(Node.class)与 stock 中的一个(Component.class)连接在一起。我对 stock (Component.class)和 catalog (Product.class)所做的工作都很好。
public List<NodeExpanded> list() {
Aggregation agg = Aggregation.newAggregation(
Aggregation.lookup(mongoTemplate.getCollectionName(Component.class),
"componentUuId", "uuId", "component")
);
AggregationResults<NodeExpanded> results = mongoTemplate.aggregate(agg, mongoTemplate.getCollectionName(Node.class), NodeExpanded.class);
return results.getMappedResults();
}
,带有一个简单的NodeExpanded类为
public class NodeExpanded implements Serializable {
private String uuId;
private Component component;
}
并且我在mongoTemplate.aggregate()指令上得到了相同的空指针异常
已解决
问题来自Sensor @ PersistenceService,它没有@自动连接MongoTemplate。 根据该帖子中提供的信息,无法找出错误原因。 再次感谢@Valijon在此任务期间的帮助^^
答案 0 :(得分:0)
可能的问题是NodeExpanded
期望使用单个Component
和Product
,但是$lookup
聚合会为两个返回array
。
如果添加额外的$project
阶段,它应该可以解决您的问题。
Aggregation agg = Aggregation.newAggregation(
Aggregation.lookup(mongoTemplate.getCollectionName(Component.class),
"componentUuId", "uuId", "component"),
Aggregation.lookup(mongoTemplate.getCollectionName(Product.class),
"component.productUuId", "uuId", "product"),
Aggregation.project()
.andInclude("uuId") //put here all fields for NodeExpanded
.and(ArrayOperators.ArrayElemAt.arrayOf("component").elementAt(0)).as("component")
.and(ArrayOperators.ArrayElemAt.arrayOf("product").elementAt(0)).as("product")
);