I've created this code from laravel:
public function findConfig($id)
{
$config = DB::table('configuration')
->join('model', 'model.configuration_id','=', 'configuration.id')
->select('configuration.id','configuration.description', 'model.name','configuration.price')
->where('configuration.id','=', $id)
->get();
$encode = json_encode($config, JSON_UNESCAPED_SLASHES);
$response = Response::make($encode, 200);
$response->header('Content-Type', 'application/json');
return $response;
}
then the return is somehow like this
[{
"id": "1",
"description": "{\"item\":[{'colours\":[\"red\",\"blue\",\"green\"]},{\"motors\":[ {\"name\":\"450W/48V\",\"price\":\"2,000\"},{\"name\":\"550W/48V\", \"price\":\"3,000\" }] } ]}",
"name": "k5-A",
"price": "300000"
},
{
"id": "1",
"description": "{\"item\":[{'colours\":[\"red\",\"blue\",\"green\"]},{\"motors\":[ {\"name\":\"450W/48V\",\"price\":\"2,000\"},{\"name\":\"550W/48V\", \"price\":\"3,000\" }] } ]}",
"name": "r-A",
"price": "300000"
}
]
How can I remove the slashes and instead of string as return type, it should be in JSON?
As lukasgeiter said, generally it isn't a good idea to store json in a db. It may get difficult to filter by that field.
If you decide to do so, and need to get the decoded data, you can use an accessor in the model. I don't know if it is the best practice. If the description is saved in the db as a json you can do this:
For the "configuration" table you may have a "Configuration" model (The official Laravel website recommends to name the table in plural, and the model in it's singular, like: table -> configurations and the model configuration). In that file you can add this:
public function getDescriptionAttribute($value)
{
return json_decode($value, true);
}
Now, the description field is returned as an array.
You can see more about accessors and mutators here: http://laravel.com/docs/4.2/eloquent#accessors-and-mutators
Related
I am using jenssegers/laravel-mongodb and i have schema is like below
Ticket Collection :
{
"_id": ObjectId("5f32d9bb486e94459b6531c3"),
"subject": "\"URGENT\" Non-Compliance In (Eastern Region)",
"content": "abc",
"user_team": "5f044199e40dfe4847056785",
"team_ids": [
"5f3012bbb7c2bc422e4da5a2"
],
"organization_id": "5f74359c7dcc8f6fbb2b47e2"
}
Team Collection :
{
"_id":ObjectId("5f3012bbb7c2bc422e4da5a2"),
"name": "Medical Maintenance",
"createTickets": true
}
Relationship in Ticket Model :
public function teams()
{
return $this->HasMany('App\Team', 'team_ids');
}
Relationship in Team Model :
public function ticket()
{
return $this->belongsTo('App\Ticket');
}
I am facing an issue to get data for teams relationship. It return an emtpry array.
Laravel version is 6.2
jenssegers/mongodb version is 3.6
Your approach to the foreign key is wrong, when in the context of hasMany. Instead a single column called team_id should be on the ticket and then you can do the following.
public function teams()
{
return $this->HasMany('App\Team', 'team_id');
}
Which would work if your ticket looks like so.
{
"_id": ObjectId("5f32d9bb486e94459b6531c3"),
"subject": "\"URGENT\" Non-Compliance In (Eastern Region)",
"content": "abc",
"user_team": "5f044199e40dfe4847056785",
"team_id":"5f3012bbb7c2bc422e4da5a2"
"organization_id": "5f74359c7dcc8f6fbb2b47e2"
}
Instead it looks like you are actually doing a many to many, because one team can have many tickets and reverse. This can be defined like so, this will probably add the data to both models, but I'm not an expert on Mongodb in Laravel.
public function teams()
{
return $this->belongsToMany(
Team::class, null, 'ticket_ids', 'team_ids'
);
}
You can find all of this in the documentation.
You could specify foreign and local keys.
Example:
public function teams()
{
$this->hasMany('App\Team', 'team_ids', '_id')
}
I'm new at Laravel and Programming at that. I have a problem joining model with its relationship, here is what my model:
class MainClass extends Model
{
public function first()
{
return $this->hasMany(First::class);
}
public function second()
{
return $this->hasMany(Second::class);
}
public function third()
{
return $this->hasMany(Third::class);
}
}
When i try to get MainClass records then load it's relationship like:
$main = Main::where('status', 'ready')->get()
$main->load(['first','second'])
Here's what i got:
[{
"id":"1",
"name":"First Person",
"status": "ready",
"first":[
{"main_id": "1", "prop":"One"},
{"main_id":"1", "prop":"Two"}],
"second":[
{"main_id": "1", "other":"Yes"},
{"main_id":"1", "other":"Two"},
{"main_id":"1", "other":"Three"}]
},{
"id":"5",
"name":"Fifth Person",
"status": "ready",
"first":[
{"main_id": "5", "prop":"Five"},
{"main_id":"5", "prop":"Six"}],
"second":[
{"main_id": "5", "other":"Laptop"},
{"main_id":"5", "other":"Pc"}]
}]
How can i merge that relationship so the result will be like join query,
this is what i want:
[{
"id":"1",
"name":"First Person",
"status": "ready",
"prop":"One",
"other:"Yes"
},{
"id":"1",
"name":"First Person",
"status": "ready",
"prop":"Two",
"other":"Two"
}]
I know there is a way to combine collection with merge or push in laravel, but i can't seem to get it right.
As of why not using join query, because i want to load relationship dynamically, so relation is not always loaded, but sometime they do. While join query, i have to write it manually (as far as i know) :-)
Maybe someone can point me somewhere, or maybe there is a package for something like this?
Thanks in advance
Use eager loading, fetching the collection, then run groupBy, then the each, then the map function to return the results formatted as your wish.
Why not just simply run the joins
You can do it with join;
$main = Main::query()->select(['main.id', 'main.name', 'main.status', 'f.prop', 's.other', 't.blabla'])
->leftJoin('first as f', 'f.main_id', 'main.id')
->leftJoin('second as s', 's.main_id', 'main.id')
->leftJoin('third as t', 't.main_id', 'main.id')
->where('main.status', 'ready')
->get();
Assume you have a GraphQL type and it includes many fields.
How to query all the fields without writing down a long query that includes the names of all the fields?
For example, If I have these fields :
public function fields()
{
return [
'id' => [
'type' => Type::nonNull(Type::string()),
'description' => 'The id of the user'
],
'username' => [
'type' => Type::string(),
'description' => 'The email of user'
],
'count' => [
'type' => Type::int(),
'description' => 'login count for the user'
]
];
}
To query all the fields usually the query is something like this:
FetchUsers{users(id:"2"){id,username,count}}
But I want a way to have the same results without writing all the fields, something like this:
FetchUsers{users(id:"2"){*}}
//or
FetchUsers{users(id:"2")}
Is there a way to do this in GraphQL ??
I'm using Folkloreatelier/laravel-graphql library.
Unfortunately what you'd like to do is not possible. GraphQL requires you to be explicit about specifying which fields you would like returned from your query.
Yes, you can do this using introspection. Make a GraphQL query like (for type UserType)
{
__type(name:"UserType") {
fields {
name
description
}
}
}
and you'll get a response like (actual field names will depend on your actual schema/type definition)
{
"data": {
"__type": {
"fields": [
{
"name": "id",
"description": ""
},
{
"name": "username",
"description": "Required. 150 characters or fewer. Letters, digits, and #/./+/-/_ only."
},
{
"name": "firstName",
"description": ""
},
{
"name": "lastName",
"description": ""
},
{
"name": "email",
"description": ""
},
( etc. etc. ...)
]
}
}
}
You can then read this list of fields in your client and dynamically build a second GraphQL query to get the values of these fields.
This relies on you knowing the name of the type that you want to get the fields for -- if you don't know the type, you could get all the types and fields together using introspection like
{
__schema {
types {
name
fields {
name
description
}
}
}
}
NOTE: This is the over-the-wire GraphQL data -- you're on your own to figure out how to read and write with your actual client. Your GraphQL javascript library may already employ introspection in some capacity. For example, the apollo codegen command uses introspection to generate types.
2022 Update
Since this answer was originally written, it is now a recommended security practice to TURN OFF introspection in production. Reference: Why you should disable GraphQL introspection in production.
For an environment where introspection is off in production, you could use it in development as a way to assist in creating a static query that was used in production; you wouldn't actually be able to create a query dynamically in production.
I guess the only way to do this is by utilizing reusable fragments:
fragment UserFragment on Users {
id
username
count
}
FetchUsers {
users(id: "2") {
...UserFragment
}
}
I faced this same issue when I needed to load location data that I had serialized into the database from the google places API. Generally I would want the whole thing so it works with maps but I didn't want to have to specify all of the fields every time.
I was working in Ruby so I can't give you the PHP implementation but the principle should be the same.
I defined a custom scalar type called JSON which just returns a literal JSON object.
The ruby implementation was like so (using graphql-ruby)
module Graph
module Types
JsonType = GraphQL::ScalarType.define do
name "JSON"
coerce_input -> (x) { x }
coerce_result -> (x) { x }
end
end
end
Then I used it for our objects like so
field :location, Types::JsonType
I would use this very sparingly though, using it only where you know you always need the whole JSON object (as I did in my case). Otherwise it is defeating the object of GraphQL more generally speaking.
GraphQL query format was designed in order to allow:
Both query and result shape be exactly the same.
The server knows exactly the requested fields, thus the client downloads only essential data.
However, according to GraphQL documentation, you may create fragments in order to make selection sets more reusable:
# Only most used selection properties
fragment UserDetails on User {
id,
username
}
Then you could query all user details by:
FetchUsers {
users() {
...UserDetails
}
}
You can also add additional fields alongside your fragment:
FetchUserById($id: ID!) {
users(id: $id) {
...UserDetails
count
}
}
Package graphql-type-json supports custom-scalars type JSON.
Use it can show all the field of your json objects.
Here is the link of the example in ApolloGraphql Server.
https://www.apollographql.com/docs/apollo-server/schema/scalars-enums/#custom-scalars
I'm using Laravel 5.2 and I have Role and Permission models with
Role.php
public function permissions()
{
return $this->hasMany('App\Permissions');
}
And if I call
return Role::with('permissions')->get()
it will return
[{
"id": 2,
"name": "training_vendor",
"display_name": "Training Vendor",
"description": "Role for vendor",
"created_at": "2016-06-23 08:05:47",
"updated_at": "2016-06-23 08:05:47",
"permissions": [
{
"permission_id": 1,
"role_id": 2
},
{
"permission_id": 2,
"role_id": 2
},
{
"permission_id": 3,
"role_id": 2
},
{
"permission_id": 4,
"role_id": 2
},
{
"permission_id": 5,
"role_id": 2
}
}]
Is it possible to change the "permissions" structure to something like these?
[{
"id": 2,
"name": "training_vendor",
"display_name": "Training Vendor",
"description": "Role for vendor",
"created_at": "2016-06-23 08:05:47",
"updated_at": "2016-06-23 08:05:47",
"permissions": [1,2,3,4,5]
}]
If you want to get an array (as title says), use toArray() method:
return Role::with('permissions')->get()->toArray();
It will convert the collection to an array.
If you need to get custom formatted JSON (as your example shows), use toArray(), then rebuild this array with using foreach or array_map()/array_filter() methods and encode result into JSON with json_encode().
I would recommend you to send data as is (without rebuilding it's structure) to frontend or whatever and work with it there.
I order to extract a Collection of permission IDs you can use the pluck() function:
$permissionIds = $role->permissions->pluck('permission_id');
You can also write a getter function in your Role model:
public function getPermissionIds()
{
return $this->permissions->pluck('permission_id');
}
and use it like:
$permissionIds = $role->getPermissionIds();
You can even override the magic __get() function:
public function __get($attr)
{
if ($attr === 'permissionIds') {
return $this->getPermissionIds();
} else {
return parent::__get($attr);
}
}
and access the permission IDs like an attribute:
$permissionIds = $role->permissionIds;
In Laravel 5.2 the returned value of models is a Collection instance which can be used to transform the result
$roles = Role::with('permissions')->get();
$roles->transform(function($role){
$role['permissions'] = $role['permissions']->pluck('permission_id')->toArray();
return $role;
});
return $roles;
This code will provide the desirable result.
Note: You can even chain the transform function after the get function.
I hope this answer will help to you,
$role = Role::all();
foreach ($role as $index){
$permissions= $index->permissions;
foreach ($permissions as $permission){
$permissionId[] = $permission->permission_id;
}
unset($index->permissions);
$index['all_permissions']= $permissionId;
}
return response()->json($role, 200);
This is work for me. So check for your code.
Pretty straightforward (I hope). I'd like to be able to use the API endpoint and have it only return specified fields. I.E. something like this
http://localhost:1337/api/reference?select=["name"]
Would ideally return something of the form
[{"name": "Ref1"}]
Unfortunately that is not the case, and in actuality it returns the following.
[
{
"contributors": [
{
"username": "aduensing",
"email": "standin#gmail.com",
"lang": "en_US",
"template": "default",
"id_ref": "1",
"provider": "local",
"id": 1,
"createdAt": "2016-07-28T19:39:09.349Z",
"updatedAt": "2016-07-28T19:39:09.360Z"
}
],
"createdBy": {
"username": "aduensing",
"email": "standin#gmail.com",
"lang": "en_US",
"template": "default",
"id_ref": "1",
"provider": "local",
"id": 1,
"createdAt": "2016-07-28T19:39:09.349Z",
"updatedAt": "2016-07-28T19:39:09.360Z"
},
"updatedBy": {
"username": "aduensing",
"email": "standin#gmail.com",
"lang": "en_US",
"template": "default",
"id_ref": "1",
"provider": "local",
"id": 1,
"createdAt": "2016-07-28T19:39:09.349Z",
"updatedAt": "2016-07-28T19:39:09.360Z"
},
"question": {
"createdBy": 1,
"createdAt": "2016-07-28T19:41:33.152Z",
"template": "default",
"lang": "en_US",
"name": "My Question",
"content": "Cool stuff, huh?",
"updatedBy": 1,
"updatedAt": "2016-07-28T19:45:02.893Z",
"id": "579a5ff83af4445c179bd8a9"
},
"createdAt": "2016-07-28T19:44:31.516Z",
"template": "default",
"lang": "en_US",
"name": "Ref1",
"link": "Google",
"priority": 1,
"updatedAt": "2016-07-28T19:45:02.952Z",
"id": "579a60ab5c8592c01f946cb5"
}
]
This immediately becomes problematic in any real world context if I decide to load 10, 20, 30, or more records at once, I and end up loading 50 times the data I needed. More bandwidth is used up, slower load times, etc.
How I solved this:
Create custom controller action (for example, 'findPaths')
in contributor/controllers/contributor.js
module.exports = {
findPaths: async ctx => {
const result = await strapi
.query('contributor')
.model.fetchAll({ columns: ['slug'] }) // here we wait for one column only
ctx.send(result);
}
}
Add custom route (for example 'paths')
in contributor/config/routes.json
{
"method": "GET",
"path": "/contributors/paths",
"handler": "contributor.findPaths",
"config": {
"policies": []
}
},
Add permission in admin panel for Contributor entity, path action
That's it. Now it shows only slug field from all contributor's records.
http://your-host:1337/contributors/paths
Here is how you can return specific fields and also exclude the relations to optimize the response.
async list (ctx) {
const result = await strapi.query('article').model.query(qb => {
qb.select('id', 'title', 'link', 'content');
}).fetchAll({
withRelated: []
}).catch(e => {
console.error(e)
});
if(result) {
ctx.send(result);
} else {
ctx.send({"statusCode": 404, "error": "Not Found", "message": "Not Found"});
}
}
I know this is old thread but I just run into exactly same problem and I could not find any solution. Nothing in the docs or anywhere else.
After a few minutes of console logging and playing with service I was able to filter my fields using following piece of code:
const q = Post
.find()
.sort(filters.sort)
.skip(filters.start)
.limit(filters.limit)
.populate(populate);
return filterFields(q, ['title', 'content']);
where filterFields is following function:
function filterFields(q, fields) {
q._fields = fields;
return q;
}
It is kinda dirty solution and I haven't figured out how to apply this to included relation entites yet but I hope it could help somebody looking for solution of this problem.
I'm not sure why strapi does not support this since it is clearly capable of filtering the fields when they are explicitly set. it would be nice to use it like this:
return Post
.find()
.fields(['title', 'content'])
.sort(filters.sort)
.skip(filters.start)
.limit(filters.limit)
.populate(populate);
It would be better to have the query select the fields rather than relying on node to remove content. However, I have found this to be useful in some situations and thought I would share. The strapi sanitizeEntity function can include extra options, one of which allows you only include fields you need. Similar to what manually deleting the fields but a more reusable function to do so.
const { sanitizeEntity } = require('strapi-utils');
let entities = await strapi.query('posts').find({ parent: parent.id })
return entities.map(entity => {
return sanitizeEntity(entity, {
model: strapi.models['posts'],
includeFields: ['id', 'name', 'title', 'type', 'parent', 'userType']
});
});
This feature is not implemented in Strapi yet. To compensate, the best option for you is probably to use GraphQL (http://strapi.io/documentation/graphql).
Feel free to create an issue or to submit a pull request: https://github.com/wistityhq/strapi
You can use the select function if you are using MongoDB Database:
await strapi.query('game-category').model.find().select(["Code"])
As you can see, I have a model called game-category and I just need the "Code" field so I used the Select function.
In the current strapi version (3.x, not sure about previous ones) this can be achieved using the select method in custom queries, regardless of which ORM is being used.
SQL example:
const restaurant = await strapi
.query('restaurant')
.model.query((qb) => {
qb.where('id', 1);
qb.select('name');
})
.fetch();
not very beautiful,but you can delete it before return.
ref here:
https://strapi.io/documentation/developer-docs/latest/guides/custom-data-response.html#apply-our-changes
const { sanitizeEntity } = require('strapi-utils');
module.exports = {
async find(ctx) {
let entities;
if (ctx.query._q) {
entities = await strapi.services.restaurant.search(ctx.query);
} else {
entities = await strapi.services.restaurant.find(ctx.query);
}
return entities.map(entity => {
const restaurant = sanitizeEntity(entity, {
model: strapi.models.restaurant,
});
if (restaurant.chef && restaurant.chef.email) {
**delete restaurant.chef.email;**
}
return restaurant;
});
},
};
yeah,I remember another way.
you can use the attribute in xx.settings.json file.
ref:
model-options
{
"options": {
"timestamps": true,
"privateAttributes": ["id", "created_at"], <-this is fields you dont want to return
"populateCreatorFields": true <- this is the system fields,set false to not return
}
}
You can override the default strapi entity response of:-
entity = await strapi.services.weeklyplans.create(add_plan);
return sanitizeEntity(entity, { model: strapi.models.weeklyplans });
By using:-
ctx.response.body = {
status: "your API status",
message: "Your own message"
}
Using ctx object, we can choose the fields we wanted to display as object.
And no need to return anything. Place the ctx.response.body where the response has to be sent when the condition fulfilled.
It is now 2023, and for a little while it has been possible to do this using the fields parameter:
http://localhost:1337/api/reference?fields[0]=name&fields[1]=something