make a nameless array out 2 diferent tables with children in php - php

I have 2 tables in my DB. 1 is full with numbers (foreign keys) and other one is full of the data I need. This is how the array should (exactly) look
"array" : [
{
"data" : "blabla"
"data2" : "blabla"
"children" : [
{
"data" : "blabla"
"data2" : "blabla"
"children" : [
{
"data" : "blabla"
"data2" : "blabla"
}
]
},
{
"data" : "blabla"
"data2" : "blabla"
"children" : [
{
"data" : "blabla"
"data2" : "blabla"
}
]
}
]
}
]
and so on, so to say.. now the right order you can find in table 1,where it is lited what the mother ID is. and i need to get the data out of table 2 so be in the array. anyone knows how to do this? i am working in codeigniter
updated with pics:

To do that, you would need to process in two steps:
You fetch each document and it's data from the two tables (let's call them "documents" and "documents_data" to build a flat array of all the documents. This way you don't have to wonder where does the data go anymore :
$results = $this->db->query("SELECT d.*, dd.* FROM documents d LEFT JOIN documents_data dd ON dd.doc_id = d.doc_id");
$documents = $results->result_array();
Now that we have everything about each document, we just need to reorder them in a recursive array using a recursive function, that will call itself with the parent id for each children and build the tree :
function getDocumentTree($documents, $idParent = null)
{
$tree = [];
foreach($documents as $document) {
if($document['doc_doc_id'] == $idParent) {
$document['children'] = getDocumentTree($documents, $document['doc_id']);
$tree[] = $document;
}
}
return $tree;
}
$tree = getDocumentTree($documents);
Note: I haven't tested this code, this is just an idea on how it works, try to understand that (especially the concept of recursivity) and implement it by yourself.

Related

Rebuilding arrays

I'm working on a tool that fetches stuff from the Wordpress database and handles it in different ways. One of the things I've done is build a simple array called $category, which contains the contents of wp_terms where term_id = <what the user picked>.
Unfortunately, it doesn't contain everything I want, so I've also populated $category->taxonomy with the relevant details from wp_term_taxonomy where term_id = <what the user picked>. It's a one-to-one relationship, so no problems there.
However, I've also got a bunch of stuff I need in wp_termsmeta, where there's a one-to-many relationship of multiple lines with the same term_id. So what I get is something like this:
{
"term_id" : 9813,
"name" : "Who's Who",
"slug" : "ww",
"term_group" : 0,
"taxonomy" :
{
"term_taxonomy_id" : 9832,
"term_id" : 9813,
"taxonomy" : "category",
"description" : "Who's Who is the CSICON Network's very own show about Doctor Who!",
"parent" : 0,
"count" : 58
},
"meta" : [
{
"meta_id" : 8490,
"terms_id" : 9813,
"meta_key" : "hosts",
"meta_value" : "1, 2"
},
{
"meta_id" : 8492,
"terms_id" : 9813,
"meta_key" : "thumbnail",
"meta_value" : "http://csicon.fm/wp-content/uploads/2015/12/ww_4-248x248.jpg"
}
]
}
We've got term_id, name, slug, and term_group from wp_terms in $category, then a bunch of stuff in $category->taxonomy and then a bunch of things under $category->meta.
And now for the problem.
If I want to access, say, the thumbnail URL, I'm going to have to traverse down to $category->meta[1]->meta_value, but I can't always know that it'll be [1]. For other categories, it might be [0] or [2]. All I know for sure is that it's the [n] that has meta_key = thumbnail.
Ideally, I would want a good way to iterate through meta and simply save the values for each meta_key as a "real" key under $category, so $category->thumbnail would return the meta_value currently stored there ... But I'll settle with a reliable way of always finding the right meta_value for a specific meta_key.
Any thoughts? :)
SOLVED
Thanks! Instead of $category['meta'] = Category::find($term_id)->catMeta;, I'm now running the following code, and it does exactly what I wanted.
$metaTemp = Category::find($term_id)->catMeta;
$metaTable = json_decode(json_encode($metaTemp), FALSE);
foreach($metaTable as $key => $value) {
$category[$value->meta_key] = $value->meta_value;
}
I would suggest converting meta from an array to an object where properties of that object would be meta_keys. So you get this structure:
{
"term_id" : 9813,
"meta" : {
"hosts" : {
"meta_id" : 8490,
"terms_id" : 9813,
"meta_key" : "hosts",
"meta_value" : "1, 2"
},
"thumbnail" : {
"meta_id" : 8492,
"terms_id" : 9813,
"meta_key" : "thumbnail",
"meta_value" : "http://csicon.fm/wp-content/uploads/2015/12/ww_4-248x248.jpg"
}
}
}
So that way search for the right meta would have a constant cost in time rather than linear.
your clients would search for it like so: $category->meta->hosts
Thanks! Instead of $category['meta'] = Category::find($term_id)->catMeta;, I'm now running the following code, and it does exactly what I wanted.
$metaTemp = Category::find($term_id)->catMeta;
$metaTable = json_decode(json_encode($metaTemp), FALSE);
foreach($metaTable as $key => $value) {
$category[$value->meta_key] = $value->meta_value;
}

PHP MongoDB query dynamic values

I want to query the content (text) inside my dynamic values keys, but i can't figure out the easiest way to do this.
So my mongo collection is like this:
{
"_id" : ObjectId("566aecb8f0e46491068b456c"),
"metadatas" : [
{
"schema_id" : "f645fabef0e464e51e8b4567",
"values" : {
"name" : "Test",
"age" : NumberLong(29),
"address" : "Test1"
},
"updated_on" : ISODate("2015-12-11T00:00:00Z")
},
{
"schema_id" : "d745fabef0e464e51e8b4567",
"values" : {
"something_else" : "lipsum"
},
"updated_on" : ISODate("2016-12-11T00:00:00Z")
}
],
}
How can i dynamically query whats inside my values since i cannot do $db->collec->find(array('metadatas.values.name' => $regex)) because i might have some other dynamic key instead of name?
thanks in advance
I ended up saving my keys uniquely on another collection and then building the query and concatenating it before applying based on #Sammaye idea:
$regex = new \MongoRegex("/^$query/i");
# First get all the dynamic keys you need to filter
$keys_to_search = $this->db->metadata_keys->find();
$this->log($keys_to_search);
$query_builder = array('$or'=>array());
foreach ($keys_to_search as $value){
array_push(
$query_builder['$or'],
array('metadatas.values.' . $value['key'] => $regex)
);
}
$this->log($query_builder);
$search_metadata_name = $this->db->filesfolders->find(
$query_builder, array('sql_fileid' => true)
);

User input for a MongoDB search

I am currently trying to accept user input so that a user may be able to search the database.
> db.test2.find().pretty()
{
"_id" : ObjectId("55de8a17f8389e208a1e7d7e"),
"name" : "john",
"favorites" : {
"vegetable" : "spinach",
"fruit" : "apple",
}
}
{
"_id" : ObjectId("55de8a17f8389e208a1f6gg4"),
"name" : "becky",
"favorites" : {
"vegetable" : "spinach",
"fruit" : "apple",
}
}
{
"_id" : ObjectId("55e3b6cbec2740181355b809"),
"name" : "liz",
"favorites" : {
"vegetable" : "spinach",
"fruit" : "banana",
}
}
In this example, the user would be able to search for any combination of a person's favorite vegetable, fruit, or both their favorite vegetable and favorite fruit. If the user entered spinach for favorite vegetable, all three would be returned. However, if the user input favorite vegetable = spinach and favorite fruit = apple, only john and becky would be returned.
In MongoDB, you are able to determine which parameter you want to search. I am trying to write my code in a way that if the user leaves a field blank, it should not be searched for.
I have tried
$query = array("favorites.vegetable" => "$userInput", "favorites.fruit" => "$userInput2");
but if either of those fields are left blank, it will not return any results. I thought about trying to use if statements:
if ($vegetable == NULL)
{
$query = array("favorites.fruit" => "$fruit");
}
else if($fruit == NULL)
{
$query = array("favorites.vegetable" => "$vegetable");
}
else
{
$query = array("favorites.vegetable" => "$vegetable", "favorites.fruit" => "$fruit");
}
but if I would like to make my database searchable by more parameters I would have too many conditional statements. Is there any way to make my Mongo search recognize when a field is left blank?
The question really is, "Where is the input coming from?". As if you have some sort of structure to the input, then the coding is quite simple to follow a pattern.
As it is, with two basic variables you can clean the code to simply contruct your query based on what is in the variables:
$query = array();
if ( $fruit != NULL ) {
$query["favorites.fruit"] = $fruit;
}
if ( $vegetable != NULL ) {
$query["favorites.vegetable"] = $vegetable;
)
Which means you either end up with a $query here that is either blank to match everything or contains the specific arguments ( either one or two ) depending on whether the content was null or not.
If your input has some structure, then you can be a lot more dynamic:
$input = array("fruit" => "apple", "vegetable" => "spinach");
$query = array();
foreach ( $input as $key => $value ) {
$query["favorites.$key"] = $value;
}
Which is doing the same thing by appending to the $query but in a much more dynamic way than with individual variables.
Also note that as far as MongoDB is concerned, then your document structure is not great. It probably really should look like this:
{
"_id" : ObjectId("55de8a17f8389e208a1e7d7e"),
"name" : "john",
"favorites" : [
{ "type": "vegetable", "name": "spinach" },
{ "type": "fruit", "name": "apple" }
]
}
And while it may initially look like the query comes out a bit more complex, removing the "specific paths" in your query for keys like "vegetable" and "fruit" have a whole lot of benefits that make life a lot easier, and also primarilly the "data" can be "indexed". Key names are not indexable for search and therefore loose efficiency:
$input = array("fruit" => "apple", "vegetable" => "spinach");
$query = array();
foreach ( $input as $key => $value ) {
$query['$and'][] = array(
'favorites' => array(
'$elemMatch' => array(
'type' => $key, 'name' => $value
)
)
);
}
Which is a nice query using $elemMatch to find documents that contain "all" array elements where "both" the "type" and "name" of the specified items in your input list.
Basically looks like this in JSON:
{
"$and": [
{ "favorites": {
"$elemMatch": {
"type": "fruit", "name": "apple"
}
}},
{ "favorites": {
"$elemMatch": {
"type": "vegetable", "name": "spinach"
}
}}
]
}
It all comes down to knowing how to manipulate data structures in your chosen language, and that "data structures" are all MongoDB queries really are, as far as your language is concerned.
As for the structure change then condider that finding people who have "vegetables" in their "favorites" now becomes this:
{ "favorites.type": "vegetable" }
Which is nice since "favorites.type" can be indexed, as opposed to:
{ "favorites.vegetable": { "$exists": true } }
Which while this can "technically" use an index, it does not really do so in such a nice way. So changing the way the schema is represented is desirable and gives more flexibility.

Sort data in sub array in mongodb

Is that possible to sort data in sub array in mongo database?
{ "_id" : ObjectId("4e3f8c7de7c7914b87d2e0eb"),
"list" : [
{
"id" : ObjectId("4e3f8d0be62883f70c00031c"),
"datetime" : 1312787723,
"comments" :
{
"id" : ObjectId("4e3f8d0be62883f70c00031d")
"datetime": 1312787723,
},
{
"id" : ObjectId("4e3f8d0be62883f70c00031d")
"datetime": 1312787724,
},
{
"id" : ObjectId("4e3f8d0be62883f70c00031d")
"datetime": 1312787725,
},
}
],
"user_id" : "3" }
For example I want to sort comments by field "datetime". Thanks. Or only variant is to select all data and sort it in PHP code, but my query works with limit from mongo...
With MongoDB, you can sort the documents or select only some parts of the documents, but you can't modify the documents returned by a search query.
If the current order of your comments can be changed, then the best solution would be to sort them in the MongoDB documents (find(), then for each doc, sort its comments and update()). If you want to keep the current internal order of comments, then you'll have to sort each document after each query.
In both case, the sort will be done with PHP. Something like:
foreach ($doc['list'] as $list) {
// uses a lambda function, PHP 5.3 required
usort($list['comments'], function($a,$b){ return $a["datetime"] < $b["datetime"] ? -1 : 1; });
}
If you can't use PHP 5.3, replace the lambda function by a normal one. See usort() examples.

MongoDB-PHP: JOIN-like query

Here are the objects:
courses
{ "name" : "Biology", "_id" : ObjectId("4b0552b0f0da7d1eb6f126a1") }
students
{
"name" : "Joe",
"classes" : [
{
"$ref" : "courses",
"$id" : ObjectId("4b0552b0f0da7d1eb6f126a1")
}
],
"_id" : ObjectId("4b0552e4f0da7d1eb6f126a2")
}
Using the PHP Mongo Class, how do I get all the students that has a biology course?
Thanks
You'll need to query twice. I dont have my environment in front of me, but something similar to what's below. I may have the "nested" portion of the second query incorrect.
// First grab the ID for the course.
$course = $collection->findOne(array("name" => "Biology"));
// Next query the students collection.
$collection->find(array("classes" => array("id" => $course['_id'])));

Categories