I have a collection that resembles this:
$a = Model::with(['sub' => function($q) {
$q->select('id', 'name')
}])->get();
This returns the following collection:
{
0: {
id: 0001,
name: "item 1",
type: "type a"
'sub' [
{
'id': 10001,
'name': "sub Item 1"
},
{
'id': 10002,
'name': "sub Item 2"
}
]
},
1: {
id: 0002,
name: "item 2",
type: "type a"
'sub' [
{
'id': 11001,
'name': "sub Item 4"
},
{
'id': 11002,
'name': "sub Item 5"
}
]
}
What I am trying to do is key the parent items by their ids and only return the relationship. For example
{
0001: {
'sub' [
{
'id': 10001,
'name': "sub Item 1"
},
{
'id': 10002,
'name': "sub Item 2"
}
]
},
0002: {
'sub' [
{
'id': 11001,
'name': "sub Item 4"
},
{
'id': 11002,
'name': "sub Item 5"
}
]
}
I cannot seem to get this to work. I have tried many variations including:
$a = Model::with(['sub' => function($q) {
$q->select('id', 'name')
}])->pluck('sub', 'id');
This doesn't work as 'Pluck' is obviously looking for a a property of the parent model with the name of 'sub' which doesn't exit. Is there a way to achieve this?
Thanks
You were almost there. You will need to do ->get() before the pluck().
$a = Model::with([
'sub' => function ($q) {
$q->select('id', 'name');
},
])->get()->pluck('sub', 'id');
The pluck() used in your example will be the query builder version of pluck rather than the collection version.
use keyBy to use your pk as array index.
https://laravel.com/docs/5.4/collections#method-keyby
However ignoring other fields you probably would need each and filter. Wouldn't it be easier to select Sub::where(...) and then use collection groupBy on the parent_id: https://laravel.com/docs/5.4/collections#method-groupby
So something like Sub::where(...)->get()->groupBy('parent_id')
Related
How to get this result:
foreach ($products as $product) {
$product->name
foreach ($product->attributes as $attribute) {
$attribute->name
foreach ($attribute->values as $value) {
$value->name
}
}
}
And
{
"name": "Product",
"attributes": [
{
"name": "Attribute 1",
"values": [
"name": "Value 1",
"name": "Value 2",
]
}
]
}
Instead of this:
foreach ($products as $product) {
$product->name
foreach ($product->attributeValues as $attributeValue) {
$attributeValue->attribute->name
$attributeValue->name
}
}
And
{
"name": "Product",
"attribute_values": [
{
"attribute_name": "Attribute 1",
"value_name": "Value 1",
},
{
"attribute_name": "Attribute 1",
"value_name": "Value 2",
}
]
}
Database
products
--- id
--- name
attributes
--- id
--- name
attribute_values
--- id
--- attribute_id
--- name
attribute_value_product
--- id
--- attribute_value_id
--- product_id
Products
Many-to-Many relationship for Attribute Values.
Attributes
One-to-Many relationship for Attribute Values.
Attribute Values
One-to-Many (Belongs To) relationship for Attributes.
Many-to-Many relationship for Products.
I'm struggling to find solution but failed so i posted here for get some solution.
Please help me.
Your desired output
"values": [
"name": "Value 1",
"name": "Value 2",
]
that is not a valid json, you cannot have an array with the same key, you either remove the key or wrap each value in array to have a key name.
Anyway, you can just define the relationship in your product to pull the Attribute Values and have a relationship in your attribute value for the attribute name,
something like this,
Produc Model
// get the attribute_values assign to products
public function attributeValues() {
return $this->belongsToMany(AttributeValue::class);
}
Attribute Value Model
// get the attribute name assign to attribute value
public function attrName() {
return $this->belongsTo(Attribute::class, 'attribute_id');
}
You can then query the related relationship and modify the attribute_values to suit your required format.
sample;
assume you have this attribute;
[{ id: 1, name: "weight" }, { id: 2, name: "style" }, { id: 3, name: "color" } ]
Create your product
Product::create([
'name' => 'Product 2'
])->attributeValues()->createMany([
['attribute_id' => 1, 'name' => '1.3kg'],
['attribute_id' => 2, 'name' => 'something nice'],
['attribute_id' => 3, 'name' => 'yellow'],
['attribute_id' => 3, 'name' => 'black'],
['attribute_id' => 3, 'name' => 'orange'],
]);
Then your product query
// eager load attribute values and attribute values name relationship
$products = Product::select('id','name')
->with(['attributeValues', 'attributeValues.attrName' ])
->paginate();
// modify and format the attribute values according to your needs before returning the products
// refer to Laravel Collection docs on how you can modify a collection and its data
$products->map( function($item) {
$item->attributes = collect($item->attributeValues)
->groupBy('attrName.id')
->values()
->map(fn ($group, $key) => [
'name' => data_get($group, '0.attrName.name'),
'values' => $group->pluck('name')->all()
])
->values();
//Remove the original attributeValues data
unset($item['attributeValues']);
return $item;
});
// Return the paginated products
return $products;
you should get a product data format like this
{
id: 2,
name: "Product 2",
attributes: [
{
name: "weight",
values: [
"1.3kg"
]
},
{
name: "style",
values: [
"something nice"
]
},
{
name: "color",
values: [
"yellow",
"black",
"orange"
]
}
]
}
Additionally, you can just append a pre-formmated custom attribute values in your Product model which will automatically loads everytime you query a product.
e.i.
Product Model
protected $appends = ['attributes'];
public function attributeValues() {
return $this->belongsToMany(AttributeValue::class);
}
protected function getAttributesAttribute() {
return $this->attributeValues()->get()
->groupBy('attrName.id')
->values()
->map(fn ($group, $key) => [
'name' => data_get($group, '0.attrName.name'),
'values' => $group->pluck('name')->all()
])
->values();
}
then you can just use
return Product::select('id','name')->paginate();
or
return Product::find(1);
and the attribute attributes will be automatically in the response
the code above uses collection methods groupBy, map, values.
Check the Collection docs for more info
I have this TKEntityProperty:
<TKEntityProperty v-tkDataFormProperty name="groups" displayName="Groups" index="2" :valuesProvider="retrieveGroups">
and this gets values from below object:
retrieveGroups:[
{key: "1", "label": "Group 1"},
{key: "2", "label": "Group 2"},
{key: "3", "label": "Group 3"}
]
but it does not multi select. I want to select multiple elements.
Is there another type of editor available ?
As #Manoj suggested, you should use AutoCompleteInline
Here is an example, it is available at Nativescript github page
data() {
return {
title: description,
booking: new Booking(),
bookingMetadata: {
'isReadOnly': false,
'commitMode': DataFormCommitMode.Immediate,
'validationMode': DataFormValidationMode.Immediate,
'propertyAnnotations': [{
'name': 'from',
'displayName': 'From:',
'index': 0,
'editor': DataFormEditorType.AutoCompleteInline,
'editorParams': {
'autoCompleteDisplayMode': AutoCompleteDisplayMode.Tokens
},
'valuesProvider': fromProviders,
},
{
'name': 'to',
'displayName': 'To:',
'index': 1,
'editor': DataFormEditorType.AutoCompleteInline,
'editorParams': {
'autoCompleteDisplayMode': AutoCompleteDisplayMode.Plain
},
'valuesProvider': ['New York', 'Washington', 'Los Angeles'],
},
]
}
};
},
I've been attempting multiple combinations of operators and can't quite get the output I want. Give an array of events:
const events = [
{ day: 1, title: 'Event 1' },
{ day: 1, title: 'Event 2' },
{ day: 1, title: 'Event 3' },
{ day: 2, title: 'Event 4' },
{ day: 2, title: 'Event 5' },
{ day: 2, title: 'Event 6' },
{ day: 'both', title: 'Sandbox 1' },
{ day: 'both', title: 'Sandbox 2' },
]
I'd like an output like so:
[
[
{
"day": 1,
"title": "Event 1"
},
{
"day": 1,
"title": "Event 2"
},
{
"day": 1,
"title": "Event 3"
}
],
[
{
"day": 2,
"title": "Event 4"
},
{
"day": 2,
"title": "Event 5"
},
{
"day": 2,
"title": "Event 6"
}
],
[
{
"day": "both",
"title": "Shared 1"
},
{
"day": "both",
"title": "Shared 2"
}
]
]
The only way I've been able to get this is by subscribing and pushing the result into another array. Ideally the rx chain would build it before subscribing, but I can't quite get it.
Here's what I have that outputs the result above:
from(events).pipe(
groupBy(obj => obj.day),
mergeMap(group => group.pipe(toArray())),
).subscribe(next => {
this.all.push(next)
console.log(this.all)
})
To accumulate the groups into an outer array, you can use another toArray operator after the mergeMap:
from(events).pipe(
groupBy(obj => obj.day),
mergeMap(group => group.pipe(toArray())),
toArray(),
).subscribe(results => console.log(results))
The resultant observable will emit only once and will emit a single array containing all of the group arrays.
I have a database of movies that I would like to nest by genre. The problem is that each movie can have multiple genres. So if I have several movies formatted like so
[
{
title : 'foo',
genres : ['Action', 'Comedy', 'Thriller']
},{
title : 'bar',
genres : ['Action']
}
]
I'd like to nest them by each individual genre so that the result would be
[
{
key: 'Action',
values: [ { title: 'foo' }, { title: 'bar'} ]
},{
key: 'Comedy',
values: [ { title: 'foo' } ]
},{
key: 'Thriller',
values: [ { title: 'foo' } ]
}
]
not directly, but you can expand your array
For example:
jj = [{ genre: ['thriller', 'comedy'], title: 'foo'}, { genre: ['thriller', 'action'], title: 'papa'}]
to expand your array:
jj2 = []
jj.forEach(function(movie) { movie.genre.forEach( function(single_genre) { jj2.push({ language: movie.language, genre: single_genre, title: movie.title } ); } ); })
Then you can perform your nesting as normal:
d3.nest().key(function(d) { return d.genre; }).entries(jj2)
Consider the following JSON values:
[
{
OrderId: 1,
OrderName: 'order 1'
OrderItems: [
{
ProductId: 1,
ProductName: "sample name"
},
{
ProductId: 2,
ProductName: "sample name 2"
}
}
}
]
I am defining a model with this structure:
var model = kendo.data.Model.define({
id: "OrderId",
fields: {
OrderId: {
type: "number",
editable: false
},
OrderName: {
type: "string",
editable: false
},
OrderItems: {
??????????????
}
}
});
Is it possible to define a model in such a way that we can change the OrderItems during the CRUD operation?
It looks like you're mixing column definitions for your controls and the model for you orders. This simplified model will help you get started with the array of order items.
var model = kendo.data.Model.define(
{
"Order": {
"OrderId": 12345,
"OrderName": "myname",
"OrderItems": [{
"ProductId": 1,
"ProductName": "sample name"
}, {
"ProductId": 2,
"ProductName": "another product"
}]
}
}
)
You can iterate through the model.Order.OrderItems collection with $.each