I have this factory
collection :
@Document(collection = "factory") public class Factory { Private List<Product> products; }
which embeds the Product
as products.
When I have to add a product to an existing factory :
@Autowired private FactoryRepository factoryRepository; public void addProduct(Long id, Product product) { Factory f = factoryRepository.findById(id); f.addProduct(product); factoryRepository.save(f); }
However, the issue is that product is a large object which contains a set of heavy attributes and the factory can have 2000 products.
So, the retrieved factory causes large memory consumption although it is not required in this phase. Is there a way to append a new product object directly into the factory document without reading the whole object?
EDIT:
As for the comments, I tried :
public void addProduct(Long id, Product product) { Document find = new Document("_id",id); Document listItem = new Document("products",product); Document push = new Document("$push", listItem); collection.updateOne(find,push); }
This gives error :
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class product
So I modified to convert it to a string before push :
public void addProduct(Long id, Product product) { Document find = new Document("_id",id); ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter(); Document listItem = new Document("products",ow.writeValueAsString(product)); Document push = new Document("$push", listItem); collection.updateOne(find,push); }
This pushed object correctly but when reading :
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.lang.String] to type [Product]
Still, I got nowhere here. Any ideas on fixing this issue?
Advertisement
Answer
You should use MongoTemplate to update product with push to add to existing products. Something like
package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import java.util.List; @SpringBootApplication public class So62173077Application { public static void main(String[] args) { SpringApplication.run(So62173077Application.class, args); } @Autowired private MongoTemplate mongoTemplate; @Document(collection = "factory") public class Factory { private Long id; private List<Product> products; } public Long createFactory() { Factory factory = new Factory(); factory.id = 1L; return mongoTemplate.insert(factory).id; } public void addProduct(Long id) { Query query = new Query(); query.addCriteria(Criteria.where("id").is(id)); Update update = new Update(); Product product = new Product(); product.name = "stackoverflow"; update.push("products", product); mongoTemplate.updateFirst(query, update, Factory.class); } private class Product { private String name; } @Bean public ApplicationRunner runner() { return args -> { //Long id = createFactory(); addProduct(1L); }; } }