How to search through unknown property name in database with Laravel - php

I'm trying to search database with json contains method of laravel. Here is my JSON of one database line:
{
"row": {
"1": {
"ID":"110555175667"
},
"2": {
"ID":"11023235667"
},
"3": {
"ID":"11001414141667"
},
"4": {
"ID":"11023235667"
},
"5": {
"ID":"1100012222225667"
},
}
}
I want to search ID, but as you see there are numbers as properties.
In example I want to find 11023235667. I've tried it like that:
->whereJsonContains('json', [['row' => ['1' => ['ID' => '11023235667']]]])
But it didn't worked. How can I do it?
EDIT:
I have also tried this:
->whereRaw('JSON_CONTAINS(json, "$.row.*.ID", "11023235667")')
I know the property of row must be JSON array to accomplish to match the id, but it has been set as JSON object

The usage of JSON_CONTAINS() accepts a JSON document as its second argument, not a path.
You could use that path to extract the ID's into an array:
SELECT JSON_EXTRACT(json, '$.row.*.ID') FROM ...
+--------------------------------------------------------------------------------------+
| ["110555175667", "11023235667", "11001414141667", "11023235667", "1100012222225667"] |
+--------------------------------------------------------------------------------------+
Using this, you can search the resulting array:
SELECT ... FROM mytable
WHERE JSON_SEARCH(JSON_EXTRACT(json, '$.row.*.ID'), 'one', '11023235667') IS NOT NULL;
You would need to do this using whereRaw() in Laravel, because Laravel doesn't have a builtin query builder function for this expression.
Tip: As soon as you reference a JSON column in the WHERE clause of an SQL query, your query becomes harder to write, and harder to optimize. This should be a red flag indicating your design is wrong. You would be better off storing data in normal rows and columns, not JSON.

Related

MongoDB simply merge two unknown Documents

Is there a way in PHP Mongodb to write an object in an already existing document and only overwrite or add the values contained in the object.
The object structure is not known to me.
Here is a sample:
existing document:
{
"package": {
"parameter": "value",
"one": "two"
}
}
php object or array:
$obj[package][parameter] = "value2"
$obj[package][new] = "test"`
result schould be
{
"package": {
"parameter": "value2",
"one": "two",
"new": "test"
}
}
I need something like array_merge()
I tried the $merge aggerator but it does not seem to work.
Unknown modifier: $merge. Expected a valid update modifier or pipeline-style update specified as an array
$merge is used to insert/update document to collection, like the UPSERT command in SQL. Have a look at $mergeObjects. Use it in combination with $replaceWith (or $replaceRoot which is just an alias)
Would be something like
{ $replaceWith: { $mergeObjects: [ "$$ROOT", {"new" : "test"} ] } }
$$ROOT is the existing object. If the existing object has any fields with the same name as your new object, then it will be overwritten with new field values. If you like to prefer the existing fields, then flip the arguments in the array.
The sample data you provided is not valid JSON, thus I cannot provide a full solution.

Search in Json column with Laravel

In my emails table, I have a column named To with column-type Json. This is how values are stored:
[
{
"emailAddress": {
"name": "Test",
"address": "test#example.com"
}
},
{
"emailAddress": {
"name": "Test 2",
"address": "test2#example.com"
}
}
]
Now I want a collection of all emails sent to "test#example.com". I tried:
DB::table('emails')->whereJsonContains('to->emailAddress->address', 'test#example.com')->get();
(see https://laravel.com/docs/5.7/queries#json-where-clauses)
but I do not get a match. Is there a better way to search using Laravel (Eloquent)?
In the debugbar, I can see that this query is "translated" as:
select * from `emails` where json_contains(`to`->'$."emailAddress"."address"', '\"test#example.com\"'))
The arrow operator doesn't work in arrays. Use this instead:
DB::table('emails')
->whereJsonContains('to', [['emailAddress' => ['address' => 'test#example.com']]])
->get()
I haven't used the json column but as the documentation refers, the below code should work fine.
DB::table('emails')
->where('to->emailAddresss->address','test#example.com')
->get();
In case to store array in json format. And just have an array list of IDs, I did this.
items is the column name and $item_id is the term I search for
// $item_id = 2
// items = '["2","7","14","1"]'
$menus = Menu::whereJsonContains('items', $item_id)->get();
Checkout the Laravel API docs for the whereJsonContains method
https://laravel.com/api/8.x/Illuminate/Database/Query/Builder.html#method_whereJsonContains
Using Eloquent => Email::where('to->emailAddress->address','test#example.com')->get();
You can use where clause with like condition
DB::table('emails')->where('To','like','%test#example.com%')->get();
Alternatively, if you have Model mapped to emails table names as Email using Eloquent
Email::where('To','like','%test#example.com%')->get();

Laravel sortBy() includes keys in the output, but sortByDesc doesn't?

I'm fetching a collection with relationship and then I try to sort by a column in one of the relationships. The output for using sortBy() is like this:
{
"1": {
"id": 1,
},
"0": {
"id": 2,
}
}
However, when I use sortByDesc() it comes out like this:
[
{
"id": 2,
},
{
"id": 1,
}
]
Is there a reason for this? It doesn't present a problem if I use it inside a Controller or View, however it is used as output in an AJAX call and breaks everything. Is there a way to have consistent output? sortByDesc() output works best for me since I don't need keys.
sortBy() and sortByDesc() behave the same way, the difference is your data.
If the sorted result has consecutive integer keys (0, 1, 2), json_encode() will return an array (your second case). Otherwise, json_encode() will return an object (your first case).
you may use something like this
$collections->sortBy(function ($collection) {
return $collection->id;
})->values();

Join table fields as a single JSON object

I am building API. I ran into issue when building responses such as this one:
{
"id": 1,
"name": "Some name",
"my_joined_table": {
"joined_table_id": "10",
"some_joined_table_field": "some value"
}
},
Joining tables as described in https://laravel.com/docs/5.2/queries would yield result such as:
{
"id": 1,
"name": "Some name",
"joined_table_id": "10",
"some_joined_table_field": "some value"
},
Instead of using join I could just run two queries, one for main table, second one for secondary and then just append second array to first one and spit JSON response, but it's a lot of queries and appending if list is big!
Example code which yields second result in pseudo-code:
$data = Model::select('id', 'name', 'my_joined_table.id as joined_table_id', 'my_joined_table.some_value some_value')
->leftJoin('my_joined_table', function($join) { //conditions_callback
})->get();
return response()->json($data);
Please advice.
EDIT2:
It seems that I can use with as follows:
$data = Model::with('my_second_table')->first();
return response()->json($data);
It does what I want, only the problem, that I cannot specify fields for both first and second tables using ->first($fields) and->with(['my_second_table' => function ($query) { $query->select('id', 'some_value'); }]) unless I specify primary key of second table in ->first($fields). How do I work around this?
TL;DR; Issue: http://laravel.io/bin/YyVjd
You can probably use Laravel Eloquent relationship to achieve it.
https://laravel.com/docs/5.2/eloquent-relationships#one-to-many
Or you can remap the returned data to a new response object using $appends.
Try something here,
http://laraveldaily.com/why-use-appends-with-accessors-in-eloquent/
This is just some clues and there is a lots work to do.
FYI, you can set $visible in your model to specify which attributes is visible.

Can I query twice to get more specific value in mongoDB?

For an example, there is a group called "A" which is an array.
And there is another group called "B" which is inside of group "A" also an array.
I want to find and update group "B" elements.
I tried to query chain-like query like in jQuery.
db.collection.findOne({"group":"A"}).findOne({"society":"B"})
something like this..
but this does not work. But main point is that I want to query group elements in group.
Any suggestion on doing this?
If you give me advice especially with PHP implementation, it will be really helpful
Maybe I am misunderstanding something, but what is wrong with:
db.collection.findOne({"group":"A", "society":"B"})
Also note that findOne only returns one document.
Assuming your document looks something like this:
db.mycol.insert( {
"_id": 1,
"group": "A",
"societies": [
{"society": "A", "name": "Alpha" },
{"society": "B", "name": "Beta" }
]
} );
Then in the Mongo shell, you can retrieve the document you want using a query:
var group = db.mycol.findOne( { "group": "A" } );
And then further filter down on its fields using some client-side JavaScript:
var societyB = group.societies.filter(function (val) {
return (val.society == "B");
} );
printjson(societyB);
You'd be able to do something similar with the PHP driver. The key is to perform the action in separate steps: first grab the document you're interested in; then filter and manipulate its fields; then save it back to the database.

Categories