I am trying to search a text field in my collection. This is an example document in my collection:
{
"_id" : ObjectId("51f9c432573906141dbc9996"),
"id" : ObjectId("51f9c432573906141dbc9995"),
"body" : "the",
"rank" : 0,
"num_comm" : 0,
"activity" : 1375323186
}
This is how I am searching...
$mongo = new MongoClient("mongodb://127.0.0.1");
$db = $mongo->requestry;
try
{
$search_results = $db->command(array('text' => 'trending', 'search' => '"the"'));
}
catch (MongoCursorException $e)
{
return array('error' => true, 'msg' => $e->getCode());
}
return array('error' => false, 'results' => $search_results);
And this is the result that I get...
{
error: false,
results: {
queryDebugString: "||||the||",
language: "english",
results: [ ],
stats: {
nscanned: 0,
nscannedObjects: 0,
n: 0,
nfound: 0,
timeMicros: 66
},
ok: 1
}
}
Below are my indexes on the collection...
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "requestry.trending",
"name" : "_id_"
},
{
"v" : 1,
"key" : {
"_fts" : "text",
"_ftsx" : 1
},
"ns" : "requestry.trending",
"name" : "body_text",
"weights" : {
"body" : 1
},
"default_language" : "english",
"language_override" : "language",
"textIndexVersion" : 1
}
Any ideas on why I get a blank results array every time?
Thanks in advance for any help!
Nathan
You can not search for "the" because it is a stop-word, and stop-words are not indexed. You can find a list of stop-words at https://github.com/mongodb/mongo/blob/master/src/mongo/db/fts/stop_words_english.txt
You can actually see what is being tried to match in the debug string:
queryDebugString: "||||the||"
The first element is empty here, which means no match is done. If you look what happens for '"cat" AND "purple"', the debug string is:
queryDebugString: "cat|purpl||||cat|purple||"
The first element(s) are now cat|purpl - this shows that stemming has also been applied for purple.
You have nested quotes on your code ('the' string literal):
$search_results = $db->command(array('text' => 'trending', 'search' => '"the"'));
Try not nesting the quotes
$search_results = $db->command(array('text' => 'trending', 'search' => 'the'));
Related
I'm trying to build an aggregation query in Parse's PHP SDK, and I'm stuck in the "lookup" area, I saw a JS example regarding this but it doesn't work in my case.
I have a table of users, which contains a "Tags" field of type Array, the array is actually an array of pointers, that point to a separate Tag class.
What I'm trying to achieve is to list most popular Tags based on their usage, so basically I need to query the users class and group the Tags that exist in the array, I already achieved this, but I'm stuck with the lookup part, the query currently returns an array of Tags pointers, what I want is to pull the object of those pointers.
Here's what I have currently:
$query = new ParseQuery('_User');
$pipeline = [
'project' => ['tags' => 1],
'unwind' => '$tags',
'group' => [
'objectId' => '$tags.objectId',
'count' => ['$sum' => 1]
],
'sort' => [ 'count' => -1],
'limit' => 10,
];
try {
return $query->aggregate($pipeline);
} catch (ParseException $ex) {
return $ex->getMessage();
}
And here's a snippet of what the _User collection looks like:
{
"_id" : "5BuBVo2GD0",
"email" : "test#test.com",
"username" : "test#test.com",
"lastname" : "Doe",
"firstname" : "John",
"_created_at" : ISODate("2017-01-23T09:20:11.483+0000"),
"_updated_at" : ISODate("2019-02-15T02:48:30.684+0000"),
"tags" : [
{
"__type" : "Pointer",
"className" : "Tag",
"objectId" : "St2gzaFnTr"
},
{
"__type" : "Pointer",
"className" : "Tag",
"objectId" : "LSVxAy2o74"
}
],
"_p_country" : "Country$4SE8J4HRBi",
}
And the Tag collection looks like this:
{
"_id" : "St2gzaFnTr",
"name" : "Music",
"_created_at" : ISODate("2018-10-22T20:00:10.481+0000"),
"_updated_at" : ISODate("2018-10-22T20:00:10.481+0000")
}
Any help would be appreciated!
Thanks in advance
Not sure if this is a direct answer, but here's a working aggregation on tags sorting for freq...
public function tagHistogram(Request $request, Response $response, array $args): Response {
$pipeline = [
'unwind' => '$tags' ,
'sortByCount' => '$tags',
'limit' => 1000,
];
$query = new ParseQuery('Product');
$result = $query->aggregate($pipeline);
$result = array_map(
function ($e) {
$e['name'] = $e['objectId'];
unset($e['objectId']);
return $e;
},
$result
);
return $response->withJson($result);
}
I have Inserted records in mongodb collection/table. everything working fine if i pass data which is available in collection like StoreId = 1
Problem: if i search data which is not available in collection like StoreId=3 then it is taking too long time to response why???? How do i simplify this issue?
Insert Data:
$data = array();
$data[] = array("StoreId" => "1","StoreName" => "abc");
$data[] = array("StoreId" => "2","StoreName" => "xyz");
$db->test->insertMany($data);
Fetch Records:
$arrFind = array(
'$and' => array(
array(
'StoreId' => "1"
),
array(
'StoreName' => array(
'$regex' => '^ab',
'$options' => 'i'
)
)
)
);
$projection = array("_id" => false);
$result = $db->test->find($arrFind,['limit'=>$data['Count'], 'projection' => $projection ]);
$array1 = iterator_to_array($result, false);
echo "<pre>";
print_r($array1);
above example working find returns output very quickly, but if i pass StoreId=3 then it is taking too long time to response blank output.
Mongodb:
db.test.find( { StoreId: "1" } ).pretty() //returns output quickly
db.test.find( { StoreId: "3" } ).pretty() //taking too-long time for blank output.
explain:
db.test.find( { StoreId: "3" } ).explain(true)
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "mydb.test",
"indexFilterSet" : false,
"parsedQuery" : {
"StoreId" : {
"$eq" : "3"
}
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"StoreId" : {
"$eq" : "3"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 0,
"executionTimeMillis" : 35083,
"totalKeysExamined" : 0,
"totalDocsExamined" : 6816823,
"executionStages" : {
"stage" : "COLLSCAN",
"filter" : {
"StoreId" : {
"$eq" : "3"
}
},
"nReturned" : 0,
"executionTimeMillisEstimate" : 34087,
"works" : 6816825,
"advanced" : 0,
"needTime" : 6816824,
"needYield" : 0,
"saveState" : 53988,
"restoreState" : 53988,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 6816823
},
"allPlansExecution" : [ ]
},
"serverInfo" : {
"host" : "Neha-PC",
"port" : 27017,
"version" : "3.6.3",
"gitVersion" : "9586e557d54ef70f9ca4b43c26892cd55257e1a5"
},
"ok" : 1
}
Hi looking at you question , it examined around 6816823 record , it seems there is no secondary index has been created
you need to create the index on "StoreId" reduced the lookup
u can check what all the index has been created for your collection using following command
db.test.getIndexKeys();
To create index you can use following command
db.test.createIndex( { StoreId: 1 } );
after creating the index on your collection try to run the query , it should be fast
for more info
https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/
Because you don't have any indexes which can be used for this query, so MongoDB need to check every document in the collection. The collection scan ("COLLSCAN") is pretty slow on big collections. You need to create an index from StoreId element.
I have the following command line mongodb query:
db.getCollection('Data').aggregate([
{'$project' : {"_id":"$_id",
"g":"$g",
"value": {'$substr':["$g",0,4]},
}
}])
The result of this query is:
{
"result" : [
{
"_id" : NumberLong(1),
"g" : "1383,09,1,2000",
"value" : "1383"
},
{
"_id" : NumberLong(2),
"g" : "1499,06,1,1",
"value" : "1499"
},
],
"ok" : 1.0000000000000000,
"$gleStats" : {
"lastOpTime" : Timestamp(0, 0),
"electionId" : ObjectId("564d7df200e15758444e9a7d")
}
}
Now I want to use this query in a php file.
Especially how can I use $substr within $project with aggregate in PHP?
You need to use the MongoCollection::aggregate method
$pipeline = array(
'$project' => array(
'g' => '$g',
'value' => array('$substr' => array('$g', 0,4))
)
);
$results = $collection->aggregate($pipeline)
So here is a sample of a document in my mongodb collection:
{
"_id" : ObjectId("561e0de61c9218b7bf9877c3"),
"Date" : NumberLong(20151014),
"Hour" : NumberLong(10),
"ProductId" : ObjectId("5614ba9c2e131caa098b4567"),
"ProductName" : "Test",
"ProducerId" : ObjectId("5617802151f8adf4db329d52"),
"ProducerName" : "Producer",
"ProducerRate" : NumberLong(300),
"ProducerMedium" : "Emailer",
"TotalLead" : NumberLong(6),
"VerifiedLead" : NumberLong(3),
"UnverifiedLead" : NumberLong(2),
"UnQualifiedLead" : NumberLong(1),
"TotalEarning" : NumberLong(660),
"Consumers" : [
{
"ConsumerId" : ObjectId("5617802151f8adf4db329d54"),
"ConsumerName" : "Consumer1",
"ConsumedRate" : NumberLong(120),
"ConsumedLead" : NumberLong(3),
"Earning" : NumberLong(360)
},
{
"ConsumerId" : ObjectId("5617802151f8adf4db329d58"),
"ConsumerName" : "Consumer2",
"ConsumedRate" : NumberLong(100),
"ConsumedLead" : NumberLong(3),
"Earning" : NumberLong(300)
}
]
}
Now i want to get the ConsumedLead grouped by ConsumerId and ProductId from the database in php.
what i have did so far to give me TotalLead and VerifiedLead grouped by product id but have no idea how to get consumerbased results for same:
$keyf = new MongoCode('function(doc) {
return {\'ProductId\': doc.ProductId,\'ProductName\': doc.ProductName};
}');
$initial = array('TotalLead'=>0,'VerifiedLead'=>0);
$reduce = "function(obj, prev) {
prev.TotalLead += obj.TotalLead;
prev.VerifiedLead += obj.VerifiedLead;
}";
$result = $collection->group($keyf, $initial, $reduce);
var_dump($result);
Any Help Please.
EDIT:
expected result wpuld be :
{ [0]=> array(4) { ["ProductId"]=> object(MongoId)#8 (1) { ["$id"]=> string(24) "5614ba9c2e131caa098b4567" } ["ProductName"]=> string(4) "Test" ["ConsumerId"]=> object(MongoId)#8 (1) { ["$id"]=> string(24) "5617802151f8adf4db329d58" } ["ConsumedLead"]=> float(4) } }
The solution is to use the aggregation framework where the operation includes an $unwind operator initial pipeline stage as this will deconstruct the Consumers array field from the input documents and outputs a document for each element. Each output document replaces the array with an element value. This will then make it possible for the $sum group accumulator operator in the $group step to work and thus givies you the required ConsumedLead grouped by ConsumerId and ProductId:
db.collection.aggregate([
{
"$unwind": "$Consumers"
},
{
"$group": {
"_id": {
"ProductId": "$ProductId",
"ConsumerId": "$Consumers.ConsumerId"
},
"TotalConsumedLead": {
"$sum": "$Consumers.ConsumedLead"
}
}
}
])
Running this aggregation operation on the above sample will result:
/* 0 */
{
"result" : [
{
"_id" : {
"ProductId" : ObjectId("5614ba9c2e131caa098b4567"),
"ConsumerId" : ObjectId("5617802151f8adf4db329d58")
},
"TotalConsumedLead" : NumberLong(3)
},
{
"_id" : {
"ProductId" : ObjectId("5614ba9c2e131caa098b4567"),
"ConsumerId" : ObjectId("5617802151f8adf4db329d54")
},
"TotalConsumedLead" : NumberLong(3)
}
],
"ok" : 1
}
So your final working aggregation in PHP should be:
$pipeline = array(
array('$unwind' => '$Consumers'),
array(
'$group' => array(
'_id' => array(
'ProductId' => '$ProductId',
'ConsumerId' => '$Consumers.ConsumerId',
),
'TotalConsumedLead' => array(
'$sum' => '$Consumers.ConsumedLead'
),
)
),
);
$out = $collection->aggregate($pipeline ,$options);
I've thoroughly searched on the internet for this but haven't found a solution.
Problem : I want to update the quantity in this document. Criteria - itemId=126260, accessDays=30
`{
"_id" : ObjectId("547acfa95ca86bec2e000029"),
"session_id" : "1111",
"email" : "aasdasda#sdfsd.com",
"isProcessed" : 0,
"couponApplied" : "",
"countryId" : 2,
"items" : [
{
"itemId" : 126260,
"batchId" : 102970,
"accessDays" : null,
"quantity" : 2
},
{
"itemId" : 126260,
"batchId" : null,
"accessDays" : 30,
"quantity" : 2
}
]
}`
I am trying to do this using PHP :
`$condition = array( "session_id"=>'1111', 'items.itemId'=>126260, 'items.accessDays'=>30);
$new_values = array( '$set' => array("items.$.quantity" => 10) );
$cart_coll->update($condition, $new_values);`
But when I run this code, it updates the first nested object instead of the second.
What am I doing wrong here ? Does mongodb not consider multiple conditions in nested objects ?
You need to use $elemMatch to get the array marker to be in the right place. So your $query becomes
$condition = array( "session_id"=>'1111',
"items" => array(
'$elemMatch'=>array("itemId"=>126260, 'accessDays'=>30)));