spring-data-mongodb: findAll() 带有输入文档列表和嵌入式 DBRef 文档的搜索参数

spring-data-mongodb: findAll() with list of input documents and search parameter for the embedded DBRef Document

我正在使用 spring-data-mongo 并尝试使用参数访问 dbref 对象。 我的项目如下所示:

我的模型如下:

我。第一个文档是 "Cars"

@Document("cars")
class CarDocument {
   @Id
   private String id;
   private String name;
   private String madeInCountry;
   private String model;
   private String madeInYear;
}

二。第二个文档是 "tools"

Document("tools")
class ToolDocument {
   @Id
   private String id;
   private String name;
   private String madeInCountry;
   private String madeInYear;
   private List<UsedIn> usedIn = new ArrayList<>();
}

三。第三个是 (ii.) 中的嵌入式模型 "UsedIn" 第三个嵌入式模型表示制造厂使用工具制造汽车的位置。

class UsedIn {
   @DBRef
   private CarDocument car;
   private DateTime usedDate;
   private String usedByUsername;
}

我的 DAO 如下:

public interface CarDAO extends MongoRepository<CarDocument, String>
{
    public CarDocument findByMadeInCountry(String madeInCountry);
}
public interface ToolDAO extends MongoRepository<ToolDocument, String>
{
    public ToolDocument findByMadeInCountry(String madeInCountry);
}

现在我需要特定汽车中使用的所有 "Tools" 的列表。 说 一种。当汽车在国家/地区制造时:"germany" 和 b.工具是在国家/地区制造的:"germany"

我看到我们不能直接在 DBRef 文档上应用搜索。 喜欢:

String madeInCountry = "germany";
toolDAO.findByMadeInCountryAndUsedInCarMadeInCountry(madeInCountry,madeInCountry);

我收到此错误:

"Invalid path reference car.madeInCountry! Associations can only be pointed to directly or via their id property!"

如何做到这一点?

我需要进行两次 DAO 调用吗? 说 一世。首先获取 madeInCountry 为 germany

的所有汽车
String madeInCountry = "germany";
carDAO.findByMadeInCountry(madeInCountry);

二。通过 carDocuments 和 String 列表查找工具。

我不知道,如何使用 CarDocuments 列表和 madeInCountry 字符串调用此 dao?

我需要使用一些 $lookup 功能吗?

谢谢

您可以尝试以下聚合。

将您的 UsedIn class 更新到下面。

 private Long carId;
 private CarDocument car;
 private Date usedDate;
 private String usedByUsername;

Mongo Shell 查询:

db.tools.aggregate([{
    "$match": {
        "madeInCountry": "germany"
    }
}, {
    "$unwind": "$usedIn"
}, {
    "$lookup": {
        "from": "cars",
        "localField": "usedIn.carId",
        "foreignField": "_id",
        "as": "usedIn.car"
    }
}, {
    "$unwind": "$usedIn.car"
}, {
    "$match": {
        "usedIn.car.madeInCountry": "germany"
    }
}, {
    "$group": {
        _id: "$_id",
        usedIns: {
            "$push": "$usedIn"
        }
    }
}])

Spring聚合码:

 Criteria toolQuery = Criteria.where("madeInCountry").in("germany");
 MatchOperation toolMatchOperation = new MatchOperation(toolQuery);
 LookupOperation lookupOperation = LookupOperation.newLookup().
                from("cars").
                localField("usedIn.carId").
                foreignField("_id").
                as("usedIn.car");
 Criteria carQuery = Criteria.where("usedIn.car.madeInCountry").is("germany");
 MatchOperation carMatchOperation = new MatchOperation(carQuery);

 TypedAggregation<ToolDocument> aggregation = Aggregation.newAggregation(ToolDocument.class, toolMatchOperation, Aggregation.unwind("usedIn"), lookupOperation, Aggregation.unwind("usedIn.car"), carMatchOperation,
                Aggregation.group("id").push("usedIn").as("usedIn"));
 List<ToolDocument> results = mongoTemplate.aggregate(aggregation, ToolDocument.class).getMappedResults();

加载数据的方法。

汽车数据

public void saveCar() {
    carDao.deleteAll();

    CarDocument carDocument1 = new CarDocument();
    carDocument1.setId(1L);
    carDocument1.setName("audi");
    carDocument1.setMadeInCountry("germany");

    carDao.save(carDocument1);
}

工具数据

public void saveTool() {

    toolDao.deleteAll();

    ToolDocument toolDocument1 = new ToolDocument();
    toolDocument1.setId(1L);
    toolDocument1.setName("wrench");
    toolDocument1.setMadeInCountry("germany");

    UsedIn usedIn1 = new UsedIn();
    usedIn1.setCarId(1L);
    usedIn1.setUsedByUsername("user");
    usedIn1.setUsedDate(new Date());

    List<UsedIn> usedIns1 = new ArrayList<>();
    usedIns1.add(usedIn1);

    toolDocument1.setUsedIn(usedIns1);

    toolDao.save(toolDocument1);
}

更新:

回答有关访问 DBRefs 的问题

ii. findTools by the list of carDocuments and String.

I dont know, how to call this dao with list of CarDocuments and madeInCountry String ?

 public List<ToolDocument> findByMadeInCountryAndUsedInCarIn(String madeInCountry, List<CarDocument> carDocuments);

就像我在第一条评论中指出的那样,您需要的第二个调用是通过带有汽车文档值列表的嵌入式 dbref 调用。当找到工具文档的匹配项时,查询将查找匹配项和 return 所有汽车文档。这意味着您将获得德国制造的工具文件,其中至少有一个用于德国制造的卡片文件。

分片更新($lookup equalivent)(想法取自这里MongoDB to Use Sharding with $lookup Aggregation Operator

List<ToolDocument> toolDocuments = toolDao.findByMadeInCountry("germany");
List<Long> carIds = toolDocuments.stream().map(tool -> tool.getUsedIn().stream().map(UsedIn::getCarId).collect(Collectors.toList())).flatMap(List::stream).collect(Collectors.toList());
List<CarDocument> carDocuments = carDao.findByMadeInCountryAndIdIn("germany", carIds);

一般来说,你不应该在 MongoDB 中建立关系。

如果您来自关系数据库,一开始可能很诱人,但在大多数情况下,在 MongoDB 中复制是一个更好的主意。

如果这对您来说不是个好主意,也许文档数据库不适合您? :)