Spring数据MongoDb聚合查找从String到ObjectId

Emm*_*uel 3 lookup-tables mongodb aggregation-framework spring-boot

我正在使用 Spring(启动)数据 2.2.7 和 mongodb 4.0。我已经设置了 3 个集合,我试图通过聚合查找操作加入它们。

  • 目录
  • 库存
  • 运营

目录

{
    "_id" : ObjectId("5ec7856eb9eb171b72f721af"),
    "model" : "HX711",
    "type" : "DIGITAL",
....
}
Run Code Online (Sandbox Code Playgroud)

映射于

@Document(collection = "catalog")
public class Product implements Serializable {

    @Id
    private String _id;
    @TextIndexed
    private String model;
....
Run Code Online (Sandbox Code Playgroud)

库存

{
    "_id" : ObjectId("5ec78573b9eb171b72f721ba"),
    "serialNumber" : "7af646bb-a5a8-4b86-b56b-07c12a625265",
    "bareCode" : "72193.67751691974",
    "productId" : "5ec7856eb9eb171b72f721af",
......
}
Run Code Online (Sandbox Code Playgroud)

映射于

@Document(collection = "stock")
public class Component implements Serializable {

    @Id
    private String _id;
    private String productId;
....
Run Code Online (Sandbox Code Playgroud)

ProductId字段引用目录集合中的_id字段

运营

{
    "_id" : ObjectId("5ec78671b9eb171b72f721d3"),
    "componentId" : ""5ec78573b9eb171b72f721ba",
    .....

}
Run Code Online (Sandbox Code Playgroud)

映射于

public class Node implements Serializable {

    @Id
    private String _id;
    private String componentId;
....
Run Code Online (Sandbox Code Playgroud)

componentId字段指的是stock集合中_id

我想查询操作库存集合以检索按 Product.model 字段(在目录集合中)排序的相应节点或组件对象列表。

虽然目标是用 Java 编码,但我尝试首先在Mongo shell中发出请求,但我什至无法让它工作,因为我试图用 ObjectId 加入(查找)字符串: Node.componentId - > 组件._id 组件.产品Id -> 产品._id

对于关系组件(库存)->产品(目录)我尝试过

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();
Run Code Online (Sandbox Code Playgroud)

但它返回没有产品信息的整个组件记录。

[{"_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}, .....]
Run Code Online (Sandbox Code Playgroud)

感谢您的帮助。


注意: 除了 @Valijon 答案能够按预期获得结果之外,返回的对象必须包含“产品”属性,否则不返回任何内容(例如使用 JSON REST 服务)

public class ComponentExpanded implements Serializable {

    private String product;
....
Run Code Online (Sandbox Code Playgroud)

AggregationResults<ComponentExpanded> results =
        mongoTemplate.aggregate(agg,mongoTemplate.getCollectionName(Component.class), ComponentExpanded.class);
Run Code Online (Sandbox Code Playgroud)

Val*_*jon 6

正如您所观察到的,问题在于productId和之间的类型不匹配_id

要连接这些数据,我们需要执行不相关的子查询,并且并非每个“新”功能都会立即将其放入抽象层,例如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();
Run Code Online (Sandbox Code Playgroud)

MongoPlayground在这里查看 shell 查询的样子。

注意:对于Java v1.7,您需要AggregationOperation如下实现:

AggregationOperation l = new AggregationOperation() {

    @Override
    public Document toDocument(AggregationOperationContext context) {
        return new Document(...); // put here $lookup stage
    }

};
Run Code Online (Sandbox Code Playgroud)