Doctrine ODM and schema-less design

后端 未结 2 1419
谎友^
谎友^ 2021-02-06 14:03

Continuing on from my question about EAV, I\'m considering using MongoDB to store product attributes.

I will store the catalogue part of this app - Categories, Products

相关标签:
2条回答
  • 2021-02-06 14:04

    Even though nothing enforces this, it is a good practice to have a basic schema for a collection. Almost all ODM's allow you to add fields not specified in the class. Assuming the application allows it, you can also leave out field values.

    The real advantage of a schemaless datastore, however, is not so much that your top level fields might vary form document to document, but that those fields can be complex data structures. Every product may have and attributes field that is an array, but the content of that array can be arbitrarily long or short, and can contain hashes with various structures. Your ODM should add an Object layer on top of these hashes if you ask it to.

    The last advantage is in upgrading the schema. In SQL adding or removing a field is a monolithic operation that is also time consuming. With a little planning, you can add or remove fields from documents as they are accessed. You simply need code to deal with the out of date schema.

    0 讨论(0)
  • 2021-02-06 14:06

    The solution is to use a @Hash

    Here is a VERY basic example I did up:

    <?php
    
    /**
     * @Document
     */
    class Product
    {
    
        /**
         * @Id
         */
        private $id;
    
        /**
         * @String
         */
        private $name;
    
        /**
         * @Hash
         */
        private $attributes = array();
    
        public function getId()
        {
            return $this->id;
        }
    
        public function setName($name)
        {
            $this->name = $name;
        }
    
        public function getName()
        {
            return $this->name;
        }
    
        public function addAttribute($name, $value)
        {
            $key = preg_replace('/[^a-z0-9\ \_]/i', '', $name);
            $key = preg_replace('/\s+/i', '_', $key);
            $key = strtolower($key);
            $this->attributes[$key] = array('value' =>$value, 'label' => $name);
        }
    
        public function getAttribute($name)
        {
            return $this->attributes[$name];
        }
    
        public function getAttributes()
        {
            return $this->attributes;
        }
    
    }
    

    Add some data:

    <?php
    
    $pen = new Product();
    $pen->setName('Cool Pen');
    $pen->addAttribute('Weight', 12);
    $pen->addAttribute('Ink Colour', 'Red');
    $pen->addAttribute('Colour', 'Black');
    
    $tv = new Product();
    $tv->setName('LED LCD TV');
    $tv->addAttribute('Weight', 12550);
    $tv->addAttribute('Screen Size', 32);
    $tv->addAttribute('Colour', 'Black');
    
    $dm->persist($pen);
    $dm->persist($tv);
    
    $dm->flush();
    

    Then query, find a product with the colour "Black" and a Screen Size greater than 20:

    <?php
    
    $query = $dm->createQueryBuilder('Catalogue\Product');
    $products = $query->field('attributes.colour.value')->equals('Black')
                    ->field('attributes.screen_size.value')->gte(20)
                    ->getQuery()->execute();
    

    I'm still not sure if this is a best way to do this and my research is still ongoing.

    0 讨论(0)
提交回复
热议问题