在不读取整个文档的情况下插入嵌入式文档 - Spring,Mongo

12

我有这个 factory 集合:

@Document(collection = "factory")
public class Factory
{
    Private List<Product> products;

}

Product嵌入产品中。 当我需要向现有工厂添加产品时:

@Autowired
private FactoryRepository factoryRepository;

public void addProduct(Long id, Product product) {
    Factory f = factoryRepository.findById(id);
    f.addProduct(product);
    factoryRepository.save(f);

}

然而,问题在于产品是一个包含一组重属性的大对象,并且工厂可以有2000个产品。因此,即使在本阶段不需要,检索到的工厂也会导致大量内存消耗。是否有一种方法可以将新产品对象直接附加到工厂文档中,而无需读取整个对象?
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);
}       

这会导致错误:
org.bson.codecs.configuration.CodecConfigurationException: 
Can't find a codec for class product

所以我修改代码,在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);
}     

这个对象被正确地推送,但读取时出现了问题:
org.springframework.core.convert.ConverterNotFoundException: 
No converter found capable of converting from type [java.lang.String] to type [Product]

然而,我在这里得不到任何进展。有没有解决这个问题的想法?


你可以尝试为这种情况实现一个不同的更新操作。这解决了你的问题吗? https://dev59.com/tGUp5IYBdhLWcg3wNFer - Benjamin Eckardt
不,将此产品对象直接转换为文档非常困难。寻找一种自动映射属性的解决方案。 - Nilanka Manoj
你的集合 factory 中有多少个 Factory 对象?是只有一个工厂持有所有产品吗?如果是这样,你应该使用集合 products,在其中可以直接插入 Product 对象。 - bkis
可能会有大约1200个工厂对象。 - Nilanka Manoj
我编辑了问题并进行了尝试。 - Nilanka Manoj
显示剩余2条评论
2个回答

6
你应该使用MongoTemplate更新产品,并使用push将其添加到现有产品中。类似以下示例:
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);

        };
    }

}

这看起来不错 :D。我想知道,是否可以使用存储库接口(即:自定义查询)来实现这一点。 - Nilanka Manoj
无法使用仓库接口进行增量更新。 - s7vr

-1

MongoDB 不鼓励使用大型数组(获取、原子操作、复杂查询)。

根据您的需求,我建议您在全新的“产品”集合中处理产品。这样可以解决您当前的问题。

祝好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接