I try to solved alphabetically sort using new MongoDB manager using command aggregation pipeline
below are my code:
$manager = new MongoDB\Driver\Manager("mongodb://localhost:27017");
$pipeline = [
[ '$match' => ['listingStatus' => ''] ],
[ '$group' => ['_id' => '$listingParticipants.email'] ],
[ '$limit' => 10 ],
[ '$skip' => 0],
[ '$sort' => ['listingParticipants.firstName' => 1]]
];
$aggregate = new \MongoDB\Driver\Command([
'aggregate' => 'Test_collection',
'pipeline' => $pipeline,
'cursor' => new stdClass
]);
$cursor = $manager->executeCommand('test_database', $aggregate);
in above code i use sort in pipeline with my string data type name field but it's not working properly so please write my code to solve this issue.
The problem here is, in a $group stage there is no name field that you are using for sort,
Better would be to sort after group
add listingParticipants.firstName in $group stage,
Also Note:
Mongo can not sort case-sensitive
meaning -- for the names like Abcd, ABcd, abcd, Bacd, bxyz
the sorted result will be (if sorted in ascending order).
Abcd, ABcd, Bacd, abcd, bxyz.
I suggest you add a new field sortName for the name with $toUpper or $toLower operator,
sortName: {$toUpper: "$name"}
and then use sortName for sorting.
Related
I write code with some array that have different structure, but I must extract the data to do something else. How can I manager these array?
The array's structure are as follow:
$a = [
'pos1' => 'somedata',
'pos2' => ['data2', 'data3'],
'pos3' => '';
];
$b = [
[
'pos1' => ['data1', 'data2', ['nest1', 'nest2']],
'pos2' => ['data1', 'data2', 'data3'],
],
['data1', 'data2'],
'data4',
];
The array's Index can be a key or a position, and the value of the corresponding index may be a array with the same structure. More tough problem is that the subarray can be nesting, and the time of the nesting has different length.
Fortunately, every array has it's owe fixed structure.
I want to convert the these array to the format as follow. When the index is a value, change it to the keyword; and if the index is a keyword, nothing changed.
$a = [
'pos1' => 'somedata',
'pos2' => [
'pos2_1' => 'data2',
'pos2_2' => 'data3'
],
'pos3' => '';
];
$b = [
'pos1' => [
'pos1_1' => [
'pos1_1_1' => 'data1',
'pos1_1_2' => 'data2',
'pos1_1_3' => [
'pos1_1_3_1' => 'nest1',
'pos1_1_3_2' => 'nest2',
],
],
'pos1_2' => [
'pos1_2_1' => 'data1',
'pos1_2_2' => 'data2',
'pos1_2_3' => 'data3',
],
],
'pos2' => ['data1', 'data2'],
'pos3' => 'data4',
];
My first solution is for every array, write the function to convert the format(the keyword will specify in function). But it is a huge task and diffcult to manage.
The second solution is write a common function, with two argument: the source array and the configuration that specify the keyword to correspondent value index. For example:
$a = [0, ['pos10' => 1]];
$conf = [
// It means that when the value index is 0, it will change it into 'pos1'
'pos1' => 0,
'pos2' => 1,
];
The common funciton will generate the result of:
$result = [
'pos1' => 0,
'pos2' => ['pos10' => 1],
]
But this solution will lead to a problem: the config is diffcult to understand and design, and other people will spend a lot of time to understand the format after conversion.
Is there are some better solution to manage these array that other people can easy to use these array?
Thanks.
I'm doing "inserts" by $push in an array inside my document, and inside it there is a field date that I want to sort it when I use the find(), but not sorting the "_id". How do I sort by date (ordens.dtOrdem)?
<?php
$mongo = (new MongoDB\Client('mongodb://localhost:27017'))->Carteira;
$collection = $mongo->ativo;
/*First way that I've tried*/
$result1 = $collection->find([].['ordens' => ['sort' => ['dtOrdem' => -1]]]);
/*Second way that I've tried*/
$result2 = $collection->find([],['ordens' => ['each' => ['ordens' => ['sort' => ['dtOrdem' = -1]]]]]);
?>
The field 'ordens.dtOrdem' is no been sorted in descending.
You cannot sort an array during a find(). You have two options:
You can specify a $sort operation during your $push to ensure that your elements are added to the array in sorted order.
You can using aggregation to sort the array on retrieval.
Solutions might look something like the following (some modification may be necessary):
// Sorting on push.
$collection->updateOne(
[...],
[ '$push' => [
'ordens' => [
// You MUST include the $each operator here or this will not work.
'$each' => [
[ 'dtOrdem' => 5 ]
],
// Where the magic happens, sorts in descending order.
'$sort'=> [ 'dtOrdem' => -1 ]
]
]]
);
// Sorting on retrieval.
$collection->aggregate([
[ '$unwind' => '$ordens' ],
[ '$sort' => [
'$ordens.dtOrdem' => -1
]],
[ '$group' => [
'_id' => '$_id',
'ordens' => [
'$push' => '$ordens'
]
]]
]);
Im retrieving data from a mysql database like following Array:
$data = [
0 => [
'id' => 1,
'Benutzer' => 'foo',
'Passwort' => '123456',
'Adresse' => [
'Strasse' => 'bla', 'Ort' => 'blubb'
],
'Kommentare' => [
0 => ['Titel' => 'bar', 'Text' => 'This is great dude!'],
1 => ['Titel' => 'baz', 'Text' => 'Wow, awesome!']
]
],
]
Data like this shall be stored in a mongo database and therefore i want to replace the keynames with translated strings that come from a config- or languagefile ('Benutzer' -> 'username').
Do i really have to iterate over the array and replace the keys or is the a better way to achieve that?
If you don't want to iterate over the array then you can change the column name in the query itself using select() function.
Considering your model name is Client then your query will be:
Client::select('Benutzer as username', '...') // you can use `trnas()` function here also
->get()
I have three working queries:
To find the rows with keyword in title field
$cursor = $collection->find(['title' => array('$regex'=>new MongoRegex($title_query))])->sort(array('timestamp'=>-1));
To find the rows with keyword in the author field
$cursor = $collection->find(['author' => array('$regex'=>new MongoRegex($author_query))])->sort(array('timestamp'=>-1));
To find the rows within a date range
$rangeQuery = array('timestamp' => array( '$gte' => $from_Id, '$lte' => $to_Id ));
$cursor = $collection->find($rangeQuery)->sort(array('timestamp'=>-1));
I want to combine the queries into 1&2, 1&3 and 2&3. However I am not able to write the correct query...
Here is my query for combining 1&2:
$cursor = $collection->find('title' => array('$regex'=>new MongoRegex($title_query)),
'author' => array('$regex'=>new MongoRegex($author_query)))->sort(array('timestamp'=>-1));
query for combining 1&3:
$rangeQuery = array('timestamp' => array( '$gte' => $from_Id, '$lte' => $to_Id ));
$cursor = $collection->find($rangeQuery, ['title' => array('$regex'=>new MongoRegex($title_query))])->sort(array('timestamp'=>-1));
Can anyone tell me how to write the correct query?
The $regex query operator should not be necessary if you are using the BSON regex type (i.e. MongoRegex in the PHP driver). Let's rewrite the original three queries:
Matching keyword in title, sorted by time descending:
$collection->find([
'title' => new MongoRegex($title_query),
])->sort(['timestamp' => -1]);
Matching keyword in author, sorted by time descending:
$collection->find([
'author' => new MongoRegex($author_query),
])->sort(['timestamp' => -1]);
Matching within a date range, sorted by time descending:
$collection->find([
'timestamp' => [
'$gte' => $from_Id,
'$lte' => $to_Id,
],
])->sort(['timestamp' => -1]);
There are several errors in the combined query examples you shared in the OP. For the "1&2" query, you were not passing an array as the first argument to find(), so that would have been a syntax error. For the "1&3" query, you're only passing the timestamp range as find() criteria, and the title regex is being incorrected passed as the second find() argument, which is reserved for specifying a project (i.e. which fields to return).
Combining the three queries is actually as easy as merging the criteria arrays. For example, we could combine all three like so:
$collection->find([
'title' => new MongoRegex($title_query),
'author' => new MongoRegex($author_query),
'timestamp' => [
'$gte' => $from_Id,
'$lte' => $to_Id,
],
])->sort(['timestamp' => -1]);
In some cases, it's not possible to merge criteria for the same field. For that reason, MongoDB has an $and query operator (see the examples for some use cases); however, in the examples above, the criteria is simple enough that you can simply combine the arrays.
here expample of my data:
'_id' => new MongoId("54087e076c03943c3c8b456b"),
'fornitureFuture' =>
array (
'0' =>
array (
'data_start'▼ => new MongoDate(1412114400, 0),
'data_end' => new MongoDate(1414710000, 0),
'f1' => '65',
'f2' => new MongoInt32(0),
'f3' => '45',
'fornitore' => new MongoId("5346cb2ab9d6f0021e6b18a0"),
),
'1' =>
array (
'data_start' => new MongoDate(1420066800, 0),
'data_end' => new MongoDate(1427752800, 0),
'f1' => '63.75',
'f2' => new MongoInt32(0),
'f3' => '70.4',
'fornitore' => new MongoId("533406896c0394a62c8b4569"),
),
i need to find if exist a data in fornitureFuture with my MongoDate between data_start and data_end ...
first group data_start is 10/01/2014 and data_end 10/31/2014
Second group data_start is 01/01/2015 and data_end 03/31/2015
Something like:
//today is 09/19/2014
$dataTest = mktime(0,0,0,date('n')+2,14,date('Y')); //return 11/14/2014
$testMese = $this->db->getOne('MyCollection', array('_id'=> new \MongoId($thisPodPdr['_id']), 'fornitureFuture.data_start'=>array('$lte'=> new \MongoDate($dataTest)) , 'fornitureFuture.data_end'=>array('$gt'=> new \MongoDate($dataTest)) ) , array('fornitureFuture'=>1) );
I expect empty response but return the record..
2 example:
$dataTest = mktime(0,0,0,date('n')+7,14,date('Y')); //return 04/14/2015
$testMese = $this->db->getOne('MyCollection', array('_id'=> new \MongoId($thisPodPdr['_id']), 'fornitureFuture.data_start'=>array('$lte'=> new \MongoDate($dataTest)) , 'fornitureFuture.data_end'=>array('$gt'=> new \MongoDate($dataTest)) ) , array('fornitureFuture'=>1) );
return correctly empty!
I need to test in the same block ...something like
'fornitureFuture.$.data_start'=>array('$lte'=> new \MongoDate($dataTest)) , 'fornitureFuture.$.data_end'=>array('$gt'=> new \MongoDate($dataTest))
but dont work .
the \ is from namespace and this->db->getOne(collection,$query,$fields) is my function like $this->collection->findOne($query,$fields);
No syntax error.
sorry for my english and thanks for the help
Your first example, which returns 2 results when you expect none, runs the following query:
[
'_id' => new MongoId(...),
'fornitureFuture.data_start' => ['$lte' => new MongoDate(1418533200)],
'fornitureFuture.data_end' => ['$gt' => new MongoDate(1418533200)],
]
The example document you provided has two array elements, with the following date ranges:
1412114400 to 1414710000
1420066800 to 1427752800
This document matches because 1412114400 (of the first element) is less than 1418533200, and 1427752800 (of the second element) is greater than 1418533200. By simply referring to fornitureFuture.data_start and fornitureFuture.data_end, MongoDB's query matcher will be satisfied if any array element's sub-field meets the criteria.
You likely want to restrict start/end criteria to same array element, in which case $elemMatch is what you're looking for:
[
'_id' => new MongoId(...),
'fornitureFuture' => [
'$elemMatch' => [
'data_start' => ['$lte' => new MongoDate(1418533200)],
'data_end' => ['$gt' => new MongoDate(1418533200)],
],
],
]
This criteria should now match only when the start/end dates of the same element satisfy the range. On a related note, you may also be interested in the $ projection operator, to limit fornitureFuture to only the matched element(s).