Question

first time in Stackoverflow. I'm trying to run a date range query on an array collection but Mongo Shell returning irrelevant documents witch doesn't match my criteria. It doesn't matter i'm doing the query trough PHP drivers, Doctrine Mongodb Query-builder or Mongo Shell.

Here is my query:

db.deals.find( { "total_sold.created_at": 
                    { $gt: new ISODate("2014-03-05T00:00:00Z"),
                      $lt: new ISODate("2014-03-05T23:59:00Z") 
                    }
               }).limit(1).pretty()

And here is the result:

    {
    "_id" : "1241412fb99a11a0bc70032a2cb6059b",

    "total_sold" : [
        {
            "some_field": "value",
            "created_at" : ISODate("2014-02-13T15:48:35Z"),
        },
        {
            "some_field": "value",
            "created_at" : ISODate("2014-02-14T10:26:19Z"),
        },
        {
            "some_field": "value",
            "created_at" : ISODate("2014-02-15T11:36:50Z"),
        },
        {
            "some_field": "value",
            "created_at" : ISODate("2014-02-17T09:35:19Z"), 
        },
        {
            "some_field": "value",
            "created_at" : ISODate("2014-02-19T16:34:52Z"),
        },
        {
            "some_field": "value",
            "created_at" : ISODate("2014-02-21T12:06:10Z"),
        },
        {
            "some_field": "value",
            "created_at" : ISODate("2014-02-24T09:52:23Z"),
        },
        {
            "some_field": "value",
            "created_at" : ISODate("2014-03-07T22:40:37Z"),
        }
    ],
    "updated_at" : ISODate("2014-03-07T22:40:40Z")
}    

I'm trying to query documents with "total_sold.created_at" fields are set to "2014-03-05" but the returning result doesn't include any sub-collections created at "2014-03-05", what's the point am I missing? I've tried $and operator, "$total_sold.created_at" notation etc. but no results.

Ps: total_sold.created_at field is indexed.

Edit: I've created and persisted my documents via Doctrine-Mongodb. Here are my Doctrine-Mongodb mappings. For the master document and total_sold sub-document.

<?php

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Gedmo\Mapping\Annotation as Gedmo;


/**
 * @ODM\Document(
 *   collection="deals",
 * )
 * @ODM\Index(keys={"total_sold"="desc"}),
 */
Class Deal {

    /**
     * @ODM\Id(strategy="NONE")
     */
    protected $id;

    /**
    *Some other fields
    **/


    /**
     * @ODM\EmbedMany(targetDocument="DealTotalSold")
     */
    protected $total_sold;


    /**
     * Constructor
     */
    public function __construct() {
        $this->total_sold = new \Doctrine\Common\Collections\ArrayCollection();
    }



    /**
     * Add totalSold
     *
     */
    public function addTotalSold($totalSold) {
        $this->total_sold[] = $totalSold;
    }

    /**
     * Remove totalSold
     *
     */
    public function removeTotalSold($totalSold) {
        $this->total_sold->removeElement($totalSold);
    }

    /**
     * Get totalSold
     *
     * @return Doctrine\Common\Collections\Collection $totalSold
     */
    public function getTotalSold() {
        return $this->total_sold;
    }

}

And this is my sub-document.

<?php

use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
use Gedmo\Mapping\Annotation as Gedmo;

/**
 * @ODM\EmbeddedDocument
 */
Class DealTotalSold {

    /**
     * @ODM\Id(strategy="NONE")
     */
    protected $id;


    /**
     * @ODM\Date
     * @Gedmo\Timestampable(on="create")
     */
    protected $created_at;

    /**
     * @ODM\Int
     */
    protected $delta_totalsold;



    public function __construct()
    {

        }

    /**
     * Set createdAt
     *
     * @param date $createdAt
     * @return self
     */
    public function setCreatedAt($createdAt)
    {
        $this->created_at = $createdAt;
        return $this;
    }

    /**
     * Get createdAt
     *
     * @return date $createdAt
     */
    public function getCreatedAt()
    {
        return $this->created_at;
    }

    /**
     * Set dealtaTotalsold
     *
     * @param Int $dealtaTotalsold
     * @return self
     */
    public function setDeltaTotalsold($dealtaTotalsold)
    {
        $this->delta_totalsold = $dealtaTotalsold;
        return $this;
    }



    /**
     * Set id
     *
     * @param custom_id $id
     * @return self
     */
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    /**
     * Get id
     *
     * @return custom_id $id
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Get deltaTotalsold
     *
     * @return float $deltaTotalsold
     */
    public function getDeltaTotalsold()
    {
        return $this->delta_totalsold;
    }


}
Was it helpful?

Solution

You have to use $elemMatch operator for matching more than one component within an array element with $and

db.deals.find({ total_sold: { $elemMatch : {
  $and:[ {created_at: {$gt: new ISODate("2014-03-05T00:00:00Z") }},
         { created_at: {$lt: new ISODate("2014-03-05T23:00:00Z") }}
        ]
  }}
});

$elemMatch Doc : http://docs.mongodb.org/manual/reference/operator/query/elemMatch/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top