Push to a nested array in Mongo with Laravel - php

I have a structure of MongoDB that looks like this:
Object_id {
workflow {
tree_id {
other_ids {...}
other_ids {...}
other_ids {...}
subscribers {
subscriber_id {
email : value
}
}
}
}
}
}
It can be clearly seen on this screen:
My MongoDB structure
I want to add an another field, for example name : last_name, under the email : value. I tried it by using this code:
Model::where('_id', '5adde78993def907b71ce503')->push(array('workflow.5ace115a93def953d254b502.subscribers.5ad09c2993def90a2c59fa59' => ['test' => 'testvalue']));
However, this code doesn't work. It shows me an error saying:
The field 'workflow.5ace115a93def953d254b502.subscribers.5ad09c2993def90a2c59fa59' must be an array but is of type object in document {_id: ObjectId('5adde78993def907b71ce503')}
Updating with ['upsert' => true] also doesn't work, because this method removes my collection and adds data. How can I add something to this array?

Structure shown by you does not have any array in it. All are document or sub documents. you can not perform array operation on non array objects. To treat Subscriber_id as an array , it should be something like this
subscriber_id [{
email : value
}]

Model::where('_id', '5adde78993def907b71ce503')->push('workflow.5ace115a93def953d254b502.subscribers.5ad09c2993def90a2c59fa59' => ['test' => 'testvalue']);
please try this.

Related

Extract particular array from multidimensional array

I have a JSON array of data that I am trying to extract particular value/keys(?) from, and would like to add them into a new array.
The array looks like this:
{ "total':2000,
"achievements":[
{
"id":6,
"achievement":{},
"criteria":{
"id":2050,
"is_completed":false
},
"completed_timestamp":1224053510000
},
{
"id":8,
"achievement":{},
"criteria":{
"id":1289,
"is_completed":true
},
"completed_timestamp":0000000
}
]
}
I want to search for true in the is_completed, and then add the id from that array into a new array.
Basically, find the id's of all the key/array (sorry unsure of terminology) where is_completed is true.
I've tried something simple like finding trying to find the key of an ID, but struggling to get that to work. And also seen some of the multi-level for loop examples but can't get them to work for my data.
Example:
$key = array_search('1289', array_column($array, 'id'));
As pointed out in the comments, you could combine array_filter (to filter completed events) and array_column (to extract their IDs).
$completedAchievements = array_filter(
$array->achievements,
static function (\stdClass $achievement): bool {
return $achievement->criteria->is_completed === true;
}
);
$completedAchievementsIds = array_column($completedAchievements, 'id');
print_r($completedAchievementsIds); // Array([0] => 8)
Note: the code above supposes your JSON was decoded as an object. If it was decoded as an array, just replace -> syntax with the corresponding array index access.
Demo

How to customize the implode function structure in resource in laravel

In my resource I've got an object like below:
return [
'something' => $this->somerelationship->implode('name',',')
];
Now it returns this result for me:
{
something [
"items,items,items"
]
}
But I want my implode to return a useable array in javascript not just making it 1 index of the array rather than that put each item in 1 slot of array-like below:
{
something
[
{items},{items},{items}"
]
}
How can I achieve that now ?
Instead of ->implode() (which takes an array and turn it into a string), try and do:
'something' => $this->somerelantionship->pluck('name')->all(),
The method pluck() returns an array with all the values from a specific key, which seems to be what you want.
You can return
json_encode($this->somerelationship->pluck('name')->toArray());
Then in your javascripts just JSON.parse() it or put it in a variable in blade:
var items = {!! json_decode($variable) !!}

Laravel - pluck with specified keys

I have a line of code similar to the following:
Sport::pluck('id', 'name)
I am dealing with frontend JavaScript that expects a list in this format:
var list = [
{ text: 'Football', value: 1 },
{ text: 'Basketball', value: 2 },
{ text: 'Volleyball', value: 3 }
...
]
I am trying to figure out how I can somehow transform the id and name values that I pluck from my model to a format similar to the Javascript list.
If that's unclear, I am looking to end up with an associative array that contains two keys: text and value, where text represents the name field on my model, and where value represents the id of the model - I hope this makes sense.
How would I approach this?
I initially tried something like this (without checking the documentation)
Sport::pluck(["id" => "value", "name" => "text]);
But that isn't how you do it, which is quite clear now. I've also tried some map-related snippet, which I cannot seem to Ctrl-z to.
Any suggestions?
Another method is to use map->only():
Sport::all()->map->only('id', 'name');
The purpose of pluck is not what you intend to do,
Please have a look at below examples,
Sport::selectRaw("id as value, name as text")->pluck("text","value");
// ['1' => 'Football', '2'=>'BasketBall','3'=>'Volleyball',...]
Syntax
$plucked = $collection->pluck('name', 'product_id');
// ['prod-100' => 'Desk', 'prod-200' => 'Chair']
Please see the documentation.
Your output is possible using simple code.
Sport::selectRaw('id as value, name as text')->get();
You could use map.(https://laravel.com/docs/5.8/collections#method-map)
$mapped = Sport::all()->map(function($item, $index) {
return [
"id" => $item["id"],
"name" => $item["text"]
];
});
This is the easiest way. Actually Laravel offers a better way for it. You can use api resources to transform your data from eloquent for the frontend:
https://laravel.com/docs/5.8/eloquent-resources
Try with toArray function:
Sport::pluck('id', 'name)->toArray();
Then you can return your result with json_encode php function;

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).

Query mongodb with php-mongo

I am building a simple messaging system, and i have a collection in mongodb with documents like this:
{ "_id" : ObjectId("50ad003f9811e5bc5c000000"), "between" : [ "user1,user2,user3" ] }
I want to perform this query:
db.conversations.find({'between': ["user1,user2,user3"]});
to get this exact document back. This query works in mongo shell.
in php-mongo, i tried this:
$collection->find(array("between"=>array("user1", "user2", "user3")));
but it does not work.
What am i doing wrong ?
Wouldn't you want to do an In query here?
db.collection.find( { "between" : { $in : ["user1", "user2", "user3"] } } );
See In query here:
Mongo Advanced $in query
making your PHP query look like:
$collection->find(array("between"=>array("$in"=>array("user1", "user2", "user3"))));
//untested, should be something similar to this.
or if you're trying to find it exactly wouldn't you just be able to do:
$collection->find(array("between"=>array("user1,user2,user3")));
First of all when you are saving your data you have to use array not a string
{ "between" : [ "user1,user2,user3" ] }
this stores in "between" an array of one element "user1,user2,user3"
Basically when you do your query in shell everything is ok, because you are asking for a array with one element. But in php you are asking for an array of three elements.
So, when you save your data, most probably that is what you need :
{ "between" : [ "user1","user2","user3" ] }
and this will give you an array of three users.
Then read the documentation http://www.mongodb.org/display/DOCS/Advanced+Queries to and adjust your query depends on what you need: either the exact array or only some elements in the array
Have you tried:
$collection->find(array("between"=>"user1,user2,user3"));
or
$collection->find(array( "$elemMatch" => array( "between"=>"user1,user2,user3" ));
The $in operator is analogous to the SQL IN modifier, allowing you to specify an array of possible matches.
Consider the following example which uses the $or operator.
$collection->find([
'select' => ['$in' => ['option 1', 'option 2', 'option 3']]
]);
References

Categories