首页 > 解决方案 > 使用可搜索的嵌套数组设计 mongodb 模式。

问题描述

我是来自关系数据库的 Mongodb 新手,我还想指出我正在使用 SpringBoot 和 JPA。如果我要建立一个汽车分类网站,其中有成千上万的用户和成千上万的列表,我将如何设置架构?我读过一些文章说规范化 nosql 数据是不好的做法。

无论如何,可以说我们有以下结构。

User
  id
  name
  email

Cars
  id
  make
  model
  year

我需要能够与用户一起列出许多汽车,我在示例中看到的是它在用户中创建了一个嵌套的汽车数组。这对于我想为用户提供所有汽车的用户帐户非常有用

我有点困惑的地方是汽车。这些汽车需要能够非常快速地被搜索到,并且不需要立即提供用户信息。在 sql 数据库中,我通常会搜索汽车(年份、品牌、型号),然后在需要时获取用户。

在 mongodb 中,您是否创建了一个包含嵌套汽车数组的用户文档?还是出于性能原因,您是否以某种方式创建了两个自动维护并针对汽车文档进行搜索的文档?

示例代码

@Document(collection = "person")
public class Person {

    @Id
    private String id;

    private String firstName;
    private String lastName;

//    @DBRef(lazy = true)
    private List<Listing> listings;

    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

@Document(collection = "listing")
public class Listing {

    @Id
    public String id;

    public String year;
    public String make;
    public String model;
    public String trim;

    public Listing(String year, String make, String model, String trim) {
        this.year = year;
        this.make = make;
        this.model = model;
        this.trim = trim;
    }
}


@Override
public void run(String... args) throws Exception {
    repository.deleteAll();

    List<Listing> listings = new ArrayList<>();
    Listing listing = new Listing("2008", "Ford", "Focus", "SE");

    //listingRepository.save(listing);

    listings.add(listing);

    Person person = new Person("Alice", "Smith");
    person.setListings(listings);
    // save a couple of customers
    repository.save(person);

    person = new Person("Bob", "Smith");

    listings = new ArrayList<>();
    listings.add(new Listing("2018", "Chrysler", "300", "S"));

    person.setListings(listings);
    repository.save(person);

    // fetch all customers
    System.out.println("Customers found with findAll():");
    System.out.println("-------------------------------");
    for (Person _person : repository.findAll()) {
        System.out.println(_person);
    }
    System.out.println();

    // fetch an individual customer
    System.out.println("Person found with findByFirstName('Alice'):");
    System.out.println("--------------------------------");
    System.out.println(repository.findByFirstName("Alice"));

    System.out.println("Persons found with findByLastName('Smith'):");
    System.out.println("--------------------------------");
    for (Person _person : repository.findByLastName("Smith")) {
        System.out.println(_person);
    }

    List<Listing> _listings = listingRepository.findAll();
    System.out.println("listings " + _listings.size());
    _listings.forEach(v -> {
        System.out.println(v.toString());
    });
}

标签: mongodbspring-boot

解决方案


按照您的实体模型,我认为您正在寻找的是类似于关系数据库中的多对多/一对多关系。因此,您可以在 MongoDb 中选择一种方式嵌入两种方式嵌入。

对于单向嵌入,您可以创建一个 Car 集合,如下所示:

db.carCollection.insertMany([{
   _id:1,
   make: 'porcha',
   model:'qwerty',
   year:'2018'
},
{
   _id:2,
   make: 'ferrara',
   model:'uiop',
   year:'2018'
}])

然后,您可以继续创建用户集合,如下所示:

db.userCollection.insert({
   _id:1,
   user:'Tom',
   email:'tom@tom.com',
   car_ids:[1,2]
})

car_ids 是一个数组,它将保存属于用户的汽车的 ID。

您可以获取属于用户的汽车(使用 findOne 获取用户。搜索参数应该是唯一的 id。我认为电子邮件在这里是唯一的。理想情况下,它应该是用户的 id):

var user=db.userCollection.findOne({email:'tom@tom.com'})
db.carCollection.find({_id:{$in:user.car_ids}})

这将为每个用户获取所有汽车

对于取车,您只需执行以下操作:

db.carCollection.find({})

对于双向嵌入,您可以在汽车集合中拥有类似的数组(如在用户集合中),以便可以将每辆车识别给其用户。


推荐阅读