Title: Doctrine Mongodb ODM Add Dynamic Dates in Aggregation
Tags: mongodb;symfony;query-builder;doctrine-odm
Question: I'm trying to know if specific motorcycle in date range has contract or not.
My schema looks like:
"_id" : ObjectId("575b7c0b0419c906e262d54b"),
"customer" : {
"id" : ObjectId("575b7c0b0419c906e262d54b")
},
"name" : "Harley Store",
"description" : "Harley Store",
"contracts" : [
{
"_id" : ObjectId("575b7c0b0419c906e262d54b"),
"bike" : {
"id" : ObjectId("575b7c0b0419c906e262d54b")
},
"from" : ISODate("2050-01-01T00:00:00.000Z"),
"till" : ISODate("2050-01-05T00:00:00.000Z"),
"cost" : 10000,
"lapse" : [
ISODate("2050-01-01T00:00:00.000Z"),
ISODate("2050-01-02T00:00:00.000Z"),
ISODate("2050-01-03T00:00:00.000Z"),
ISODate("2050-01-04T00:00:00.000Z"),
ISODate("2050-01-05T00:00:00.000Z")
]
},
{
"_id" : ObjectId("575b7c0b0419c906e262d54c"),
"bike" : {
"id" : ObjectId("575b7c0b0419c906e262d54c")
},
"from" : ISODate("2050-01-01T00:00:00.000Z"),
"till" : ISODate("2050-01-05T00:00:00.000Z"),
"cost" : 10000,
"lapse" : [
ISODate("2050-01-06T00:00:00.000Z"),
ISODate("2050-01-07T00:00:00.000Z"),
ISODate("2050-01-08T00:00:00.000Z"),
ISODate("2050-01-09T00:00:00.000Z")
]
}
]
I have the following query in the mongo shell:
db.getCollection('BikeStore').aggregate([
{
$unwind:'$contracts'
},
{
$project:{
contract:'$contracts',
_id: 0
}
},
{
$match:{
'contract.bike.id': ObjectId("575b7c0b0419c906e262d54b")
}
},
{
$match:{
$or: [
{'contract.lapse': {$eq: ISODate("2049-01-31T00:00:00.000Z")}},
{'contract.lapse': {$eq: ISODate("2050-02-01T00:00:00.000Z")}},
{'contract.lapse': {$eq: ISODate("2050-02-02T00:00:00.000Z")}}
]
}
}
])
The query in mongo shell works fine, but the dates are generated dynamically from-till and I can not find the way to get this done using query builder.
My query builder:
public function hasContracts(string $bikeId, \DateTime $from, \DateTime $till): bool
$filterDate = \DateTimeImmutabl75b5:f2c1:f5d7:b954:8dc3:cee9:baf:a8c0createFromMutable($from);
$days = $from->diff($till)->days;
$qb = $this->createAggregationBuilder();
$qb->unwind('$contracts');
$qb->project()
->field('contract')
->expression('$contracts')
->field('_id')
->expression(0);
$qb->match()->field('contract.bike.id')->equals(new ObjectId($bikeId));
for($i;$days){ //$i menor or equal $days
$qb->match()->addOr(
$qb->matchExpr()->field('contract.lapse')->equals(
new UTCDateTime(
$filterDate->add(
\DateInterval75b5:f2c1:f5d7:b954:8dc3:cee9:baf:a8c0reateFromDateString(sprintf('%d day', $i)))
->setTime(0, 0)->getTimestamp() * 1000
)
)
);
}
return 0 !== $qb->execute()->count();
The query that generates the odm is the following:
"aggregate": true,
"pipeline": [
{
"$unwind": "$contracts"
},
{
"$project": {
"contract": "$contracts",
"_id": 0
}
},
{
"$match": {
"contract.bike.id": {
"$oid": "575b7c0b0419c906e262d54b"
}
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2524780800000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2524867200000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2524953600000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525040000000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525126400000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525212800000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525299200000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525385600000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525472000000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525558400000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525644800000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525731200000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525817600000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525904000000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2525990400000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526076800000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526163200000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526249600000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526336000000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526422400000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526508800000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526595200000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526681600000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526768000000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526854400000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2526940800000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2527027200000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2527113600000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2527200000000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2527286400000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2527372800000"
}
}
}
]
}
},
{
"$match": {
"$or": [
{
"contract.lapse": {
"$date": {
"$numberLong": "2527459200000"
}
}
}
]
}
}
],
"options": {
"cursor": true
},
"db": "store",
"collection": "BikeStore"
How do I add the dates dynamically into the match and not duplicate the match ?
Thx for you help!!!

Here is the accepted answer: Each time you call $qb-&gt;match() you're creating a new $match stage. This should do:
$qb-&gt;match();
for($i;$days){ //$i menor or equal $days
$qb-&gt;addOr(/* ... */);


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 0, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2018:00:11/13/18', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<mongodb><symfony><query-builder><doctrine-odm>', 'Title': 'Doctrine Mongodb ODM Add Dynamic Dates in Aggregation', 'ViewCount': 608, 'id': 53285524, 'user_AboutMe': None, 'user_AccountId': 3094980.0, 'user_DisplayName': 'user2620369', 'user_Reputation': 173.0, 'user_Views': 9.0, 'user_id': 2620369.0}}