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?
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);
};
}
}
MongoDB large array may be discouraged (fetching, atomic operations, complex querying).
Depending on your needs but I would suggest you to deal with Product in a brand new "product" collection. Your current issue will be solved as well.
Regards.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.