Spring -data-mongodb: findAll () with a list of input documents and a search parameter for the embedded DBRef document

I am using spring -data-mongo and trying to access dbref objects with parameters. My project is as follows:

My models are as follows:

I am. The first document is "Cars"

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

II. The second document is "tools"

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

III. The third is the “UsedIn” built-in model in (ii). The third built-in model is a tool used to make cars in a production house.

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

My DAO is as follows:

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

Now I need a list of all the “tools” that are used in a particular car. Say a. when the car is made InCountry: "germany" and b. tool made by InCountry: "germany"

I see that we cannot apply search directly in DBRef documents. eg:

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

I get this error:

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

How to do it?

Do I need to make two DAO calls? I say. first get all cars with madeInCountry - this is Germany

 String madeInCountry = "germany"; carDAO.findByMadeInCountry(madeInCountry); 

II. findTools by list of carDocuments and String.

I do not know what to call this dao with a list of CarDocuments and madeInCountry String?

Do I need to use some functions of $ lookup?

thanks

+6
source share
2 answers

You can try aggregation.

Update the UsedIn class below.

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

Mongo Shell Query:

 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 Aggregation Code:

  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(); 

Ways to load data.

Vehicle Details

 public void saveCar() { carDao.deleteAll(); CarDocument carDocument1 = new CarDocument(); carDocument1.setId(1L); carDocument1.setName("audi"); carDocument1.setMadeInCountry("germany"); carDao.save(carDocument1); } 

Tool data

 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); } 

Update:

To answer the question about access to DBRefs

II. findTools by list of carDocuments and String.

I do not know what to call this dao with a list of CarDocuments and madeInCountry String?

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

As I noted in the first comment, the second call you need is a call to the built-in dbref with a list of the cost of automotive documents. The request will search for a match and return all the documents of the car if a match is found for the tool document. This means that you will receive documentary documents that are made in Germany, which are at least used in a card document made in Germany.

Remaining Update ( $lookup equalivent) (Idea taken from here by MongoDB for using Sharding with the $ 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); 
+3
source

in general, you should not establish relationships in MongoDB.

You might be tempted at first if you came from relational databases, but in most cases duplication is the best idea in MongoDB.

if that doesn't seem like a good idea to you, maybe the document database is simply not for you? :)

0
source

Source: https://habr.com/ru/post/1015558/


All Articles