春季数据MongoDb聚合查找级联

时间:2020-05-23 19:50:33

标签: mongodb spring-boot aggregation-framework cascade lookup-tables

我在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在此任务期间的帮助^^

1 个答案:

答案 0 :(得分:0)

可能的问题是NodeExpanded期望使用单个ComponentProduct,但是$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")
);