mongodb php $push not inserting array - php

I've seen a bunch of the other Mongo PHP $push questions up here on SO, but for some reason none of what they're saying is working, so I'm posting my own version.
Basically, I'm trying to follow a guideline set by 10gen where representing something like a news feed or blog/comment post should be done using buckets - making documents that hold a certain number (50) of events (comments, etc.), and then creating multiple documents as the content grows.
What I'm trying to do is push documents ($event) into an array (events), but there seems to be some confusion with PHP when the document doesn't exist (upserting). I tried to do it with an insert, but insert and $push don't play well together.
Here's what I have right now:
$historyDoc = array('_id'=>$uID, 'count'=>1,
array('$push' => array('events' => $event)));
$query = array('_id'=>$uID);
//add user to history
$collection->update($query,$historyDoc,
array('safe'=>true,'timeout'=>5000,'upsert'=>true));
Where $event is a properly-formatted array (document) of things (e.g. timestamp, userID, action, name) and $uID is a MongoID object taken from another collection.
The result that I get is this:
{
"_id": {
"$oid": "4f77ec39fef97a3965000000"
},
"0": {
"$push": {
"events": {
"timestamp": 1333259321,
"action": "achievement",
"pts": 0,
"name": "join"
}
}
},
"count": 1
}
Which is good, because my document is at least showing up right, but how the hell is there a key with a "$" in it? It's not like I'm failing to escape the $...I've been very intently using single quotes for that exact reason.
Maybe there's something I'm missing, or maybe I broke PHP, but I've been wrestling with this one for awhile and there's nothing I can thing of. It's holding my whole project up, so....>:/

Your update document is ill-formed, try this:
$historyDoc = array('_id' => $uID,
'count' => 1,
'$push' => array('events' => $event));

It's not the most elegant solution, but it looks like it works. Apparently there's a problem with using $push on a new document (insert or upsert) (EDIT: It might actually be the issue with combining atomic and non-atomic thing that's the problem. You can't use atomic operators on _id, so...). However, you can get around it by inserting the document first and then updating/upserting it.
In order to initialize an array in Mongo via PHP, you need to create a document with an empty array a a value, as seen here:
$historyDoc = array('_id'=>$uID.'-0',
'count'=>1,
'events'=>array());
From there, you can simply take what you were going to put into the first index and upsert it later:
$collection->update($query, $historyDoc,
array('safe'=>true,'timeout'=>5000,'upsert'=>true));
$collection->update($query,
array('$push'=>array('events'=>$event)),
array('safe'=>true,'timeout'=>5000,'upsert'=>true));
This yields a resulting document of the form:
{
"_id": "4f77f307fef97aed12000000-0",
"count": 1,
"events": [
{
"timestamp": 1333261063,
"action": "achievement",
"pts": 0,
"name": "join"
}
]
}
Source: Mongo PHP Manual - Updates

Related

What is the correct way to apply a sub filter to a term in Elastic search?

I have a query I am trying to fetch results via Elastic Search 6.4.2.
It is working. But when I apply the Tags part which should be under the NewsArticle type, it brings back results for the CaseStudyPage type.
Am I doing this correctly?
Basically I want to sub filter tags on the NewsArticle type but it doesn't seem to work correctly.
I have tried many different formats which I have found on StackOverflow and various web pages.
"highlight":{
"pre_tags":[
""
],
"post_tags":[
"<\/strong>"
],
"fields":{
"*":{
}
},
"require_field_match":false,
"fragment_size":100,
"number_of_fragments":3,
"highlight_query":{
"query_string":{
"query":"",
"analyze_wildcard":true,
"default_operator":"AND"
}
}
},
"sort":[{"PublishedDate":"desc"}],
"size":5000,
"query":{
"bool":{
"filter":{
"bool":{
"should":[
{
"terms":{
"ClassName":[
"CaseStudyPage"
]
}
},
{
"bool":{
"must": [
{
"terms":{
"ClassName":[
"NewsArticle"
]
}
},
{
"terms":{
"Tags.ID":[
"9"
]
}
}
]
}
}
]
}
}
}
}
}
No error messages. It brings back results for both CaseStudyPage and NewsArticle which both have the Tag.ID = 9. But it should only bring back CaseStudyPage (Full results) and NewsArticle results that only have the Tag.ID = 9.
The results return tagged content from the CaseStudyPage type and the NewsArticle type, but it should only display the tagged content from the NewsArticle type and all the CaseStudyPage type.
First of all, for debuging purposes, I'd remove the "highlight" section & also the "sort" (I'm not sure if a document gets filtered out if the sort field - in your case 'PublishedDate' is empty? probably not)
Now, focusing on the query itself; it appears that your problem (If i undrestood correctly) is that the "Tags flter term query" is not working, because you are receiving in your result all CaseStudyPage and NewsArticle, even tough for those last ones you want specifically the ones with a Tags.ID = 9 (right?).
I believe your Tags.ID is an integer type right?, if so please remove the quotes arround the 9 (if you didn't create a mapping before indexing specifying your Tags.ID was indeed an "int" type, then the elasticsearch created a type mapping for the field based on your first insert, please verify that you Tags.ID is either a "not analyzed String - KEYWORD" or an integer; this is necessary for filter queries & terms queries to work properly).
Another possibility could be that the 'className' field contains several values? for example CaseStudyPage and NewsArticle both like an array? if so; then your should block will pick all those documents containing "CaseStudyPage" independently on the "NewsArticle" being prsent, or the TAGS.ID value. But this is rather unlikely.
I'd create a small filter query where I'd only test that you are correctly filtering the documents with the Tags.ID = 9; and after you've got that working, the you can put that filter again in the must block. The rest
of your query looks fine.
EDIT: btw if for the 'CaseStudyPage' filter, you explicitly want entries that are not tagged, then you also need to add a' must not' block for that, or must with !=
Hope it helps.

How to organize JSON for faster info access?

I've been experimenting with storing Vehicle info as JSON for a quicker way to access the vehicle images.
I have set up a table in my DB for JSON. The JSON is set up as shown below. All the vehicles are in this one JSON, along with all their image information. I'm not sure if this is the best way of storing the data. I want to be able to quickly search based on the VIN to get only the images associated with that VIN.
My Issues:
The loading speed of dynamically displaying associated vehicle images.
Not getting ONLY the associated images; other vehicle images are showing
Not sure if my JSON format makes sense (or is inefficient), haven't worked too much with JSON
Is there an easier way to set up the SQL table for querying a specific JSON?
Possible Solutions (not limited to one):
Re-format JSON for simple referencing
Re-format Table for easier queries
Edit "code loops" for faster run time
I had previously set up loops on the InventoryPage, this is a dynamic page that uses $_GET to get the associated VIN, to iterate through my Database to get the images associated with the VIN. This worked, but took too long due to the amount of iterations required.
There are usually much more entries than this, I trimmed it way back for easier readability. We have an average of 100 vehicles with 20-60 images per vehicle.
Here is an example of my JSON format:
[{"vin": "JF1GR89658L827860", "images": [{"image":
"https://cdn04.carsforsale.com/3/420970/23594569/1133776572.jpg?
dt=100320180034", "width": 800, "height": 600}, {"image":
"https://cdn04.carsforsale.com/3/420970/23594569/1133776606.jpg?
dt=100320180034", "width": 800, "height": 600}]},
{"vin": "6Y86G433753", "images": [{"image":
"https://cdn04.carsforsale.com/3/420970/23684711/1135715340.jpg?
dt=100620180134", "width": 800, "height": 600}, {"image":
"https://cdn04.carsforsale.com/3/420970/23684711/1135715371.jpg?
dt=100620180134", "width": 800, "height": 600}]}]
The code I currently have to iterate through the JSON and find the associated images, which I think incorrectly displays images from different vehicles:
foreach ($vehicles as $vehicle)
{
if ($vehicle['vin'] === $vin) {
$last_element = ',';
while ($vehicle['images']) {
echo "{";
echo "src: '" . $vehicle['images'][0]['image'] . "',";
echo "h: " . $vehicle['images'][0]['height'] . ",";
echo "w: " . $vehicle['images'][0]['width'];
echo "}" . $last_element;
}
break;
}
}
Expected output from above "code loops" (for image slider):
{
src: "image_link",
h: vehicle_height,
w: vehicle_width
}
Don't try to create JSON by hand. Construct an array with all the data, then call json_encode().
$json_array = array();
foreach ($vehicles as $vehicle)
{
if ($vehicle['vin'] = $vin) {
foreach ($vehicle['images'] as $image) {
$json_array[] = ['src' => $image['image'], 'h' => $image['height'], 'w' => $image['width']];
}
break;
}
}
echo json_encode($json_array);
You might also consider making the JSON column an object rather than an array, with vin as the keys. Then you wouldn't need a loop, you could just use $vehicle[$vin]. You could also use JSON_SEARCH() in your MySQL query to just extract that element instead of the whole array.
This is kind of an opinionated answer, but I really don't see the benefit of using a JSON column for this. I think it looks like the data you have is a better fit for traditional related tables. I think JSON columns are great for storing more unstructured data, sets of different objects with different properties. But you have a set of similar objects, each a flat list with exactly the same properties. Image records would fit perfectly in their own table, possibly with a relationship to a different table with other VIN-related data, and I think retrieving related data would be simpler and more efficient that way. Just my two cents, and I know it doesn't really answer the question directly, but it's a bit much for a comment.

how to get values of an array that is inside an object?

i've got an object that contains two elements, the first is a string, the second one is an array, i need to return only the array.
here is the object :
{
"return_code": 0,
"response": [
{
"tid": "30",
"categorie": "Fish"
},
{
"tid": "31",
"categorie": "Birds"
}
]
}
I want to return the "response". Any help please ?
Thank you.
Here's the basic idea based on new comments:
Decode the JSON string you're getting using json_decode in PHP. This will give you a PHP object.
Create an empty list to contain the elements you want in the result.
For each element in the response property of the decoded JSON object, add response.categorie to your list container.
Return the now full list
Your data looks like JSON, so I will propose a solution in jq ("Json Query") - a language that is readily available on most modern computing platforms -- see https://stedolan.github.io/jq/
The originally posted task was to find the array. In jq, this can be accomplished using the program: .response
Subsequently, the task was revised to extracting the "categorie" values.
This can be accomplished using the program: .response[] | .categorie
Here is an example, assuming your input is in a file named "input.json":
$ jq '.response[] | .categorie' input.json
"Fish"
"Birds"
Or, if you want to gather these values as a JSON array:
$ jq - '[.response[] | .categorie]' input.json
["Fish","Birds"]

json_decode fails

I'm fairly new to json, and I'm having an issue with json_decode. I think I know why, but I haven't been able to sort out how to fix it.
Basically, I have a URL that supplies json info. I grab it using cURL, and return it as a PHP variable, and that's working just fine. I can print_r out all the info I want. However, when I use json_decode($json, true), it returns NULL.
I THINK it's because, technically, what's being returned is not a string, but more like an object - and I can't sort out how to grab the contents of that object.
For example, when I return the json stuff as a php variable:
print_r($json);
The output returned looks like so (I won't do it exactly, because it's HUGE, so I'll show you the layout to keep it simple)
MyThing.returnedItems({MyThing.returnedItems({
"projects":[{
"completed":"2010-12-21",
"status":"finished",
"favorited":0,
"started":"2010-12-20",
"percentage":78,
"permalink":"slug to post",
"size":"One size",
"thumbnail":{"src":"full path to full size image",
"medium":"full path to thumbnail"},
"name":"Some title here",
"notes":"description here",
"url":"URL to page",
"comments":0},
So you can see it's like a nested array. I don't mind that, but I'd like to be able to access all the key/value pairs of these arrays as PHP variables. But it seems because of the "MyThing.returnedItems()" surrounding it, it doesn't see it as a string to decode, so I get a NULL value every time.
Anyone know what I'm missing here? Once I figure out how to grab the stuff inside there, I think I've got it (simple foreach or whatnot to get the rest of the variables as needed), but I just can't seem to get in there.
This is valid JSON
{
"item1": [
{
"something": [],
"something else": "some value"
}
],
"another fun thing": [
{
"more fun": "fun value 1",
"even more!": "fun value 2"
}
],
"item2": {
"another thing": "another value"
}
}
This is not!
MyThing.returnedItems({
"item1":[{"something:[],
"something else": "some value"},
"another fun thing": [{"more fun": "fun value 1",
"even more!": "fun value 2"}]
],
"item2":{"another thing": "another value"}
})
Its a javascript method call
Okay, I just wanted to add that you all REALLY helped me out. Especially MaX, because by knowing the "official term" of what was happening, I had better searches and ended up finding some really interesting code that eventually landed me my solution. However, I did discover the reason why I was having my json wrapped in that weird function method call: the URL that the site gave me to access their API actually had that call in it, so it was returned wrapped in it. In other words, the json file URL I had was like so:
somesite.com/apicall.json?key=1234567890&callback=MyThing&version=0...
so as soon as I removed that "callback" section - BAM the json was no longer wrapped, and a whole new world of foreach functions opened up to me. So, even though the solution ended up being a REALLY stupid oversight on my part, I wanted to thank you all for your input, because I learned a whole lot of stuff I wasn't planning to today XD
Oh, and the code that actually ended up working (after I got rid of the callback part of the URL, because json_decode was still returning NULL on me) was this:
$data = json_decode(file_get_contents($json), true);
print_r($data); // array of everything available for me to mess with!
Thanks again for your help, everyone :) I REALLY appreciate it!

How to generate json response using php

How to generate json response using php
In the model:
public function groups($getGroupId) {
$cols = array('group_id','name');
$sql = $this->select ()
->from ( $this->_name, $cols )
->where ( 'parent_id=?', $getGroupId );
$groupDetails = $this->fetchAll ( $sql );
//$childGroupName = $groupDetails['name'];
return $groupDetails;
}
groupDetails.php page:
$dbGroup = new dbGroups();
$groupDetails = $dbGroup -> groups($getGroupId);
$jsonResponse = json_encode($groupDetails);
print_r($jsonResponse);
When printing the data i'm getting response like this
[{"group_id":"2","name":"ABCD"},{"group_id":"7","name":"XYZ"}]
But i want output like this, Because i have to generate a jstree using json
[
{
"data" : {
"icon" : <optional>,
"title" : <node name>
},
"attr" : {
"rel" : <the type you defined in the js (maybe "group")>,
"title" : <node title>,
"id" : <the node's id / group id>
},
"state" : "closed"
}
]
I would recommend that you use the output from json_encode as it is. Takes less bandwidth. Only reason I see for all the whitespace is for debugging, and for that I'd rather use FireBug and/or JSONView in FireFox.
Anyways, if you really want to, you can maybe try the JSON_PRETTY_PRINT flag? Seems this was added in 5.4.0 though, so maybe not the version you're on supports it... There seems to be options you can use for that in the comments there though. Maybe you can find something useful? http://www.php.net/manual/en/function.json-encode.php#102091
You say you have to create a jstree now, and that doesn't really have anything to do with what you're asking. You're two examples of data doesn't look anything alike at all. json_encode does not do anything special or magic. It just takes data and turns it into JSON. It's your job to make that data look correctly first, before encoding it. Your DB query most likely returns a set of flat rows, and you'll have to loop through it and somehow generate your tree the way you want it. You can probably find other questions here about how to create tree structures out of flat DB results.
Since you are using Zend Framework, I recommend you to use Zend_Json. Zend_Json is a pretty useful component to use in order to format Json from any supported format (object, array, xml...).
Zend_Json::decode() and Zend_Json::encode() will allow you to encode and decode Json and prettyPrint() is used to make your output prettier.
Edit:
As Svish said, your two examples doesn't look alike, so it's kind of hard to guess what you want to put inside your tree.
What you need is to create your own array, so you can make it look like the way you want.
For example, let's say you only want one row from your database in your tree, then your array would be something like this:
$v = array(
array(
"data" => array("icon" => "ICON",
"title" => $row->name),
"attr" => array("rel" => "REL",
"title" => "TITLE",
"id" => $row->group_id),
"state" => "closed"));
echo Zend_Json::encode($v);
These lines should echo something like in your examples.
To make it works with your fetchAll(), a simple foreach will do it.

Categories