MongoDB Support

Overview

MongoDB is one of the most popular NoSQL document-oriented database, used for its high write load (useful for analytics or IoT) and high availability (easy to set replica sets with automatic failover). It can also shard the database easily for horizontal scalability and has a powerful query language for doing aggregation, text search or geospatial queries.

API Platform uses Doctrine MongoDB ODM 2 and in particular its aggregation builder to leverage all the possibilities of the database.

Doctrine MongoDB ODM 2 relies on the mongodb PHP extension and not on the legacy mongo extension.

Enabling MongoDB Support

If the mongodb PHP extension is not installed yet, install it beforehand.

If you are using the API Platform Distribution, modify the Dockerfile to add the extension:

 // api/Dockerfile

 ...
 	pecl install \
 		apcu-${APCU_VERSION} \
+		mongodb \
 	; \
 ...
 	docker-php-ext-enable \
 		apcu \
 		opcache \
+		mongodb \
 	; \
 ...

Then rebuild the php image:

docker-compose build php

Add a MongoDB image to the docker-compose file:

# docker-compose.yml

# ...
  db-mongodb:
      # In production, you may want to use a managed database service
      image: mongo
      environment:
          - MONGO_INITDB_DATABASE=api
          - MONGO_INITDB_ROOT_USERNAME=api-platform
          # You should definitely change the password in production
          - MONGO_INITDB_ROOT_PASSWORD=!ChangeMe!
      volumes:
          - db-data:/var/lib/mongodb/data:rw
          # You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data!
          # - ./docker/db/data:/var/lib/mongodb/data:rw
      ports:
          - "27017:27017"
# ...

Once the extension is installed, to enable the MongoDB support, require the Doctrine MongoDB ODM bundle package using Composer:

docker-compose exec php composer req doctrine/mongodb-odm-bundle:^4.0.0@beta doctrine/mongodb-odm:^2.0.0@beta

Execute the contrib recipe to have it already configured.

Change the MongoDB environment variables to match your Docker image:

# api/.env

MONGODB_URL=mongodb://api-platform:!ChangeMe!@db-mongodb
MONGODB_DB=api

Change the configuration of API Platform to add the right mapping path:

# api/config/packages/api_platform.yaml

api_platform:
    # ...

    mapping:
        paths: ['%kernel.project_dir%/src/Entity', '%kernel.project_dir%/src/Document']

    # ...

Creating Documents

Creating resources mapped to MongoDB documents is as simple as creating entities:

<?php
// api/src/Document/Product.php

namespace App\Document;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ApiResource
 *
 * @ODM\Document
 */
class Product
{
    /**
     * @ODM\Id(strategy="INCREMENT", type="integer")
     */
    private $id;

    /**
     * @ODM\Field
     * @Assert\NotBlank
     */
    public $name;

    /**
     * @ODM\ReferenceMany(targetDocument=Offer::class, mappedBy="product", cascade={"persist"}, storeAs="id")
     */
    public $offers;

    public function __construct()
    {
        $this->offers = new ArrayCollection();
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function addOffer(Offer $offer): void
    {
        $offer->product = $this;
        $this->offers->add($offer);
    }

    public function removeOffer(Offer $offer): void
    {
        $offer->product = null;
        $this->offers->removeElement($offer);
    }

    // ...
}
<?php
// api/src/Document/Offer.php

namespace App\Document;

use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ApiResource(iri="http://schema.org/Offer")
 *
 * @ODM\Document
 */
class Offer
{
    /**
     * @ODM\Id(strategy="INCREMENT", type="integer")
     */
    private $id;

    /**
     * @ODM\Field
     */
    public $description;

    /**
     * @ODM\Field(type="float")
     * @Assert\NotBlank
     * @Assert\Range(min=0, minMessage="The price must be superior to 0.")
     * @Assert\Type(type="float")
     */
    public $price;

    /**
     * @ODM\ReferenceOne(targetDocument=Product::class, inversedBy="offers", storeAs="id")
     */
    public $product;

    public function getId(): ?int
    {
        return $this->id;
    }
}

Some important information about the mapping:

  • Identifier fields always need to be integers with an increment strategy. API Platform does not support the native ObjectId.
  • When defining references, always use the id for storing them instead of the native DBRef. It allows API Platform to manage filtering on nested properties by using lookups.

Filtering

Doctrine MongoDB ODM filters are practically the same as Doctrine ORM filters.

See how to use them and how to create custom ones in the filters documentation.

Creating Custom Extensions

See how to create Doctrine MongoDB ODM custom extensions in the extensions documentation.