mongo : get one attribute from a - php

in mongo shell or PHP
how do I retreive the "list" attribute of this document ?
{
"_id" : ObjectId("51b972ebe4b075a9690bbc5b"),
"list" : [
"Environnement",
"Toutes thématiques",
"Transports"]
}
I'm looking how to do
db.tags.list would return all the 'list' attributes of documents in mycollection
The answer was :
db.tags.findOne().list

If you need all of the list attributes across all documents in the tags collection, you may want to use the db.collection.find() method (MongoCollection::find() in PHP).
$tags = array();
foreach ($collection->find() as $document) {
if (empty($document['list'] || ! is_array($document['list'])) {
continue;
}
foreach ($document['list'] as $tag) {
$tags[] = $tag;
}
}
Offhand, if these documents had other fields that you didn't need, you could use the second argument to provide a projection to find() and limit the fields returned. In this case, { list: 1 } would do it.
Taking this a step further, if you wanted to quickly retrieve all of the unique tags across the list fields in the collection's documents, you could use the distinct database command (MongoCollection::distinct() in PHP.
Assuming the collection had the following documents:
> db.foo.insert({x:['a','b','c']})
> db.foo.insert({x:['a','c','d']})
The following method would execute the distinct database command and return the array [ "a", "b", "c", "d" ]:
$uniqueTags = $collection->distinct('list');

If you want to access your document directly:
document['list']
If you are accessing a collection:
db.collection.findOne({_id: ObjectId("51b972ebe4b075a9690bbc5b")}).list

Related

How To Search In Multiple Columns In Json File Array?

I have a json file with this content :
[
{
"id": "apple",
"symbol": "app",
"name": "Apple",
},
]
I Want To Search In This Json File In id Or symbol Or name Columns,
I Write This Code :
$nameOrIDOrSymbol="apple"; // user types id or symbol or name.
$names= json_decode(file_get_contents("file.json", true), true);
$name_key1 = array_search($nameOrIDOrSymbol,array_column($names, 'id')
$name_key2 = array_search($nameOrIDOrSymbol,array_column($names, 'name');
$name_key3 = array_search($nameOrIDOrSymbol,array_column($names, 'symbol');
if($name_key1){
var_dump($name_key1);
}elseif($name_key2){
var_dump($name_key2);
}elseif($name_key3){
var_dump($name_key3);
}
How Can I Search In This Three 3 Array Columns Only Once With array_search Or Another Function? For example search like this :
$name_key = array_search($nameOrIDOrSymbol,array_column($names, 'id','name','symbol')
Currently you search first in the 'id' column, then in the 'name' column, and finally in the 'symbol' column. If, at any stage, you encounter a match you return the array key. If you want to keep this functionality you have to look through the columns in that order.
You could combine the three columns into one array, juggle a bit with the keys, and do a single search that way, but I don't think that's very efficient.
Why not restructure you code a bit? For instance like this:
$query = 'apple';
$columns = ['id', 'name', 'symbol'];
$data = json_decode(file_get_contents('file.json', true), true);
foreach ($columns as $column) {
$key = array_search($query, array_column($data, $column);
if ($key !== false) break;
}
var_dump($key);
Now you've only used array_search() once, in a way.
This code is more efficient than yours because it stops searching as soon as it has found 'apple' in a column. Your code always searches through all columns.
Note that I actually check that array_search() returns false, unlike what you did, which would not have responded when this functions returned key zero.
Also note that, if ever the need arises, you can now easily add more columns without having to add more repeating lines of code.

How to make update endpoint more general purpose? (PHP)

I have a function in my API to update the name of a person in an SQLite database. You give it the ID of the name you wish to change and the new name.
How can I build a function in a way that allows me to update a wide range of fields in the database? even things from different tables?
I started off trying to use parameters to switch which SQL query is executed, but this feels a bit clunky and not scalable. Is there a better way?
Current code:
private function json_update_authors() {
$input = json_decode(file_get_contents("php://input"));
$query = "UPDATE authors SET name = :name WHERE authorId = :authorId";
$params = ["name" => $input->name, "authorId" => $input->authorId];
$res = $this->recordset->getJSONRecordSet($query, $params);
return json_encode(array("status" => 200, "message" => "ok"));
}
Prependix
You can achieve what you want, but before reading the details, I recommend contemplating about what you would like to restrict this to, because if there is a file your function blindly trusts, then, should malicious input be inside that file, your database can easily be hacked. So, you should have a whitelist of tables/fields that you allow to be updated and apply that.
Decoding JSON
json_decode decodes your JSON into an object that you do not foresee its members. However, according to the documentation you can iterate this object like:
foreach ($obj as $key => $value) {
echo "$key => $value\n";
}
However, json_decode can decode your JSON into an array as well, like:
$input = json_decode(file_get_contents("php://input"), true);
I personally prefer to decode JSON into arrays, but you can operate with the first approach as well. In both cases, you can iterate the array in a similar manner as described above.
Recommended format
Your update has an anatomy as follows:
table
fields
filter
So, I would recommend that you could use a JSON representation of your input, that has a tableName field, which is a string, a fields field, which is an array of key-value pairs, the keys representing the fields to be updated and the values representing the values to update to and finally a filter field, which, if we intend to be very elegant, could also be an array of objects of key-value pairs, the keys representing the fields you are to filter by and the values representing the values you would filter with. A sample Javascript object that would comply to this format would look like the following:
[
{ //Your query
tableName: 'authors',
fields:
[
{
name: 'somename'
}
],
filters:
[
{
authorId: 123
}
]
},
{ //Some other example
tableName: 'books',
fields:
[
{
isbn: 'someisbn',
title: 'sometitle'
}
],
filters:
[
{
pageNumber: 123,
weight: '5kg'
}
]
},
]
I have given an example above, of two objects, so you can see that:
several updates can be notified in the JSON
you can update several fields in a single command
you can filter by several fields
I should mention that this is a rabbit hole, because you might want to vary the operator as well, but since this is a mere answer, I do not write a full elegant project for its purpose. Instead of that, let me just tell you that there is a lot of room for improvement, operator dynamicity springs to mind instantly as an improvement that you may need.
How to generate an update query:
//assuming that $JSON is a variable holding such values as describe in the previous chapter
foreach ($JSON as $obj) {
$tableName = $obj['tableName'];
$fields = [];
$filters = [];
$params = [];
$toExecute = isset($whiteList['tables'][$tableName]);
foreach ($obj['fields'] as $key => $value) {
$fields[]=($key.'=:field_value'.$key);
$params['field_value'.$key] = $value;
$toExecute = $toExecute && isset($whiteList['fields'][$key]);
}
foreach ($obj['filters'] as $key => $value) {
$filters[]=($key.'=:filter_value'.$key);
$params['filter_value'.$key] = $value;
$toExecute = $toExecute && isset($whiteList['filters'][$key]);
}
}
I have used a whitelist above to make sure that the queries will not update tables/fields using filters where the name of the table/field/filter is either badly formatted, malicious or unwanted. This code is untested, it might well contain typos, but the idea should be a good starting point.

Laravel 5: How to put multiple items into the same key in a collection without overriding?

Trying to figure out how to parse a collection and put multiple items into the same key in another collection.
Currently I'm doing this using an array and then I make a collection out of it, but the items inside are not of type Collection, each key is an array and I can't use methods like first() on those arrays. Yes, I can use [0] instead, but I'd prefer to have access to methods available for collections.
$some_array = [];
// Parsing the existing collection using foreach
foreach ($items_collection as $item) {
// Doing some checks
if ($item->some_attribute1 == 1
&& #$item->some_relation->some_attribute2
) {
// Putting the item into the array with a specific dynamic key
$some_array[$item->some_relation->some_attribute2][] = $item->some_relation;
}
else if ($item->some_attribute1 == 0
&& #$item->some_relation->some_attribute3) {
// Putting the item into the array with a specific dynamic key
$some_array[$item->some_relation->some_attribute3][] = $item->some_relation;
}
}
// Defining a new Collection
$new_collection = new Collection();
// Parsing the array of groups of items and putting them in the newly created Collection by their key
foreach ($some_array as $key => $key_items) {
$new_collection->put($key, $key_items);
}
If to make something like this
$some_collection = new Collection();
foreach ($items_collection as $item) {
if ($item->some_attribute1 == 1
&& #$item->some_relation->some_attribute2
) {
$some_collection->put($item->some_relation->some_attribute2, $item->some_relation);
}
else if ($item->some_attribute1 == 0
&& #$item->some_relation->some_attribute3) {
$some_collection->put($item->some_relation->some_attribute3, $item->some_relation);
}
}
then instead of storing all the items in the same key the new items will just override the old ones. Is there a way to put multiple items in the same key using put()?
Thank you in advance!
Seems that the issue was that I wasn't converting the $key_items into a collection in the last foreach.
Now I just used the collect() method on $key_items to make it into a Collection and everything works now.
foreach ($some_array as $key => $key_items) {
$new_collection->put($key, collect($key_items));
}
I hope someone will find this workaround useful until a more elegant solution will be found.

How do I complete this explode & comparison query properly? Laravel 5.3

I'm trying to get this string of tags and iterate through it to get the respective tag's columns on another table:
1A-3,1-1,1-2,3-4,4-6,4-8,6-13,6-15,8-6,8-11,7A-4,7A-5,7A-6
Checks against:
$ministry = AgencyLogin::find(196);
$prefs = $ministry->Ministry_Preferences;
$tags = explode(',', $prefs);
foreach ($tags as $tag) {
$sub_categories[] = DB::table('descriptor')
->where('tag', $tag)
->select('subcategory', 'description')
->first();
}
//dd($sub_categories);
return view('agencydash', compact('sub_categories'));
dd($prefs) prints the correct string. $sub_categories[] never converts to an actual array, so can't be parsed like one, and my limited experience in Laravel means I don't know how to turn a query like this into an array instead the current thing it is, an object.
dd($sub_categories) after I treat it as an object prints a single result which seems to be random:
{#262 ▼
+"subcategory": "SUPPORT ROLE"
+"description": "Project Management"
}
I've been teaching myself Laravel and php steadily, so problems like this open more questions then I can answer yet.
Anybody know what I'm missing?
Why are you iterating through $tags and not using whereIn method and getting a whole collection of relevant rows?
$ministry = AgencyLogin::find(196);
$prefs = $ministry->Ministry_Preferences;
$tags = explode(',', $prefs);
$sub_categories = DB::table('descriptor')
->whereIn('tag', $tags)
->get(['subcategory', 'description']);
//dd($sub_categories);
return view('agencydash', compact('sub_categories'));
Docs

Remove item from array in a mongodb document using Doctrine ODM

I have a mongoDB document comprising the following structure:
{
"_id" : ObjectId("537b9731fa4634134c8b45aa"),
"kpis" : [
{
"id" : 4,
"value" : 3.78,
"entered" : Timestamp(1401377656, 9)
}
]
}
I want to remove ALL kpi documents where the id is x. This is quite simple to do on the database directly using the pull command:
db.lead.update({}, {$pull:{"kpis":{id:5}}}, {multi:true});
However my (several) attempts to match this syntax using the doctrine ODM have failed:
$qb->update()
->field('kpis')
->pull($qb->expr()->field('kpis.id')->equals($kpi->getId()))
->multiple(true)
->getQuery()
->execute();
// I've also tried..
$qb->update()
->field('kpis')
->pull($qb->expr()->field('kpis')->elemMatch(
$qb->expr()->field('kpis.id')->equals($kpi->getId())
))
->multiple(true)
->getQuery()
->execute();
Nothing is removed. Am I using the query builder correctly?
I believe you want to do the following:
$qb->update()
->field('kpis')->pull(array('id' => $kpi->getId()))
->multiple(true)
->getQuery()
->execute();
You can use the Query::debug() method to dump the actual query generated by this. You should expect the following in the dumped newObj field:
{ "$pull": { "kpis": { "id": <number> }}}
To explain why your previous examples didn't work:
->field('kpis')
->pull($qb->expr()->field('kpis.id')->equals($kpi->getId()))
Here, you're creating the following query:
{ "$pull": { "kpis": { "kpis.id": <number> }}}
This would only match:
If each embedded object in the top-level kpis array had an embedded kpis object within it, which in turn had an id field that matched the number.
If the embedded objects in the top-level kpis array had their own kpis arrays consisting of embedded objects with an id field that matched. This would be MongoDB's array element matching coming into play.
In your second example, you have:
->field('kpis')
->pull($qb->expr()->field('kpis')->elemMatch(
$qb->expr()->field('kpis.id')->equals($kpi->getId())
))
This would generate the following query:
{ "$pull": { "kpis": { "$elemMatch": { "kpis.id": <number> }}}}
I've never seen such syntax before, but I think the $elemMatch is superflous, since $pull already takes criteria to match an array element as its argument. $elemMatch is useful in a query when you're directly matching on an array field and don't mean to do a full equality match against the array elements (i.e. you want to provide criteria instead of an exact match).

Categories