I'm trying to grasp the purpose and usage of api filters, and the doc I find on the net is extremely sparse, including "https://api-platform.com/docs/core/filters".
From what I understand, the typeFilters allow the api user to filter according to a given strategy (e.g don't retrieve data where dates are null), right?
Writing a filter annotation on the class level is equivalent to writing it on every property of the targetted type, right?
I'd like to understand the group filter, but there is not one example of that. What am I supposed to understand from the class annotation * #ApiFilter(GroupFilter::class, arguments={"parameterName"="foobargroups"})? foobargroup is not used anywhere else in the codebase. Not within the DummyCar.php example nor in another class, ang google doesn't find me even one working example.
What I need is a way to tell the api to return only a part of the entity or another. Would groupFilter do? Or is that only used to handle 1-N relationship?
Those are serializer filters.
if you have an Entity like
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Serializer\Filter\GroupFilter;
use ApiPlatform\Core\Serializer\Filter\PropertyFilter;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* #ApiResource
* #ApiFilter(PropertyFilter::class)
* #ApiFilter(GroupFilter::class)
*/
class User {
/**
* #Groups({"list"})
*/
public $email;
public $firstname;
public $lastname;
/**
* #Groups({"list"})
*/
public $age;
}
When sending a GET request to /users, the collection in JSON-LD for example should look like
{
...
"hydra:members": [
{
"#id": ...,
"#type": ...,
"email": "john-email#dre.ss",
"firstname": "John",
"lastname": "Doe",
"age": 30
},
{
"#id": ...,
"#type": ...,
"email": "jane-email#dre.ss",
"firstname": "Jane",
"lastname": "Doe",
"age": 20
}
]
...
}
When using the property filter, sending a GET request to /users?properties[]=email&properties[]=firstname, the collection would look like
{
...
"hydra:members": [
{
"#id": ...,
"#type": ...,
"email": "john-email#dre.ss",
"firstname": "John"
},
{
"#id": ...,
"#type": ...,
"email": "jane-email#dre.ss",
"firstname": "Jane"
}
]
...
}
When using the group filter, sending a GET request to /users?groups[]=list, the collection would look like
{
...
"hydra:members": [
{
"#id": ...,
"#type": ...,
"email": "john-email#dre.ss",
"age": 30
},
{
"#id": ...,
"#type": ...,
"email": "jane-email#dre.ss",
"age": 20
}
]
...
}
I hope it helps to understand.
Writing a filter annotation on the class level is equivalent to
writing it on every property of the targetted type, right?
This is true for ORM filter, not serializer filter
Finally, using #ApiFilter(GroupFilter::class, arguments={"parameterName"="foobargroups"}) is to allow you to change the query parameter property if for instance you have a "real" property called groups. Then instead of sending the GET request to /users?groups[]=list, you would send /users?foobargroups[]=list
Related
I created a model NearMiss that has a many-to-many relationship with a Type model. When there is a GET request for a specific NearMiss, I want an array to be attached to the JSON output that has the name attribute of all Type instances that belong to the NearMiss instance.
I can attach an array of Types to the output, but I want to get rid of all the additional information (such as pivot information).
The GET request /nearmisses/{nearmiss} executes the following method:
public function show($id)
{
try {
$nearmiss = NearMiss::findOrFail($id)->first();
$nearmiss->types->makeHidden(['id', 'created_at', 'updated_at']);
return response()->json($nearmiss);
} catch(ModelNotFoundException $e) {
abort(400, 'Model not found');
}
}
The NearMiss model has the following types relation:
public function types()
{
return $this->belongsToMany('App\Type', 'near_miss_type', 'near_miss_id', 'type_id');
}
Current output:
{
"id": 1,
"location_long": "0.0000000",
"location_lat": "0.0000000",
"employee_id": 1,
"created_at": "2019-02-11 16:38:24",
"updated_at": "2019-02-11 16:38:24",
"types": [
{
"id": 1,
"name": "Brandgevaar"
"created_at": "2019-02-11 16:33:25",
"updated_at": "2019-02-11 16:33:25",
},
{
"id": 2,
"name": "Slipgevaar",
"created_at": "2019-02-11 16:34:12",
"updated_at": "2019-02-11 16:34:12",
}
]
}
I know that I can remove additional attributes (such as id, created_at, updated_at), but that still leaves me with an array of Type instances (with just a single name attribute). When I try flatten() I receive an error that flatten() can't be used on BelongsToMany relationships.
Desired output:
{
"id": 1,
"location_long": "0.0000000",
"location_lat": "0.0000000",
"employee_id": 1,
"created_at": "2019-02-11 16:38:24",
"updated_at": "2019-02-11 16:38:24",
"types": [
"Brandgevaar", "Slipgevaar"
]
}
Can someone help me to get the desired output please.
You could load the types manually and use the pluck() function to only get the name of each type.
$nearmiss->types = $nearmiss->types()->pluck('name');
However I'm not sure if this will interfere with the magic properties from Eloquent.
So I'm trying to generate my own configuration metadata from #ConfigurationProperties items, following documentation available at https://docs.spring.io/spring-boot/docs/current/reference/html/configuration-metadata.html#configuration-metadata-annotation-processor. Note that I'm using Spring Boot 2.0 and Kotlin.
It works fine, except for one thing: the defaultValue fields are not getting filled with my default values, but instead just contain standard values like 0 or false.
My #ConfigurationProperties file looks like this:
#Component
#ConfigurationProperties("flowr.epg")
class EpgProperties {
/** Whether or not schedules should be computed/refreshed on (re)start */
var refreshOnRestart = true
/** Number of threads used to store new images */
var nImagesUploadThreads = 10
}
The result looks like this:
{
"hints": [],
"groups": [
{
"sourceType": "com.taktik.flowr.epg.properties.EpgProperties",
"name": "flowr.epg",
"type": "com.taktik.flowr.epg.properties.EpgProperties"
}
],
"properties": [
{
"sourceType": "com.taktik.flowr.epg.properties.EpgProperties",
"defaultValue": false,
"name": "flowr.epg.refresh-on-restart",
"description": "Whether or not schedules should be computed\/refreshed on (re)start",
"type": "java.lang.Boolean"
},
{
"sourceType": "com.taktik.flowr.epg.properties.EpgProperties",
"defaultValue": 0,
"name": "flowr.epg.n-images-upload-threads",
"description": "Number of threads used to store new images in Ozone",
"type": "java.lang.Integer"
}
}
The documentation is kind of poor about that defaultValue field. Am I doing something wrong? Is it possible to fill that defaultValue field automatically? If yes, what am I doing wrong?
Most of the other methods in the language api, such as analyze_syntax, analyze_sentiment etc, have the ability to return the constituent elements like
sentiment.score
sentiment.magnitude
token.part_of_speech.tag
etc etc etc....
but I have not found a way to return name and confidence in isolation from classify_text. It doesn't look like it's possible but that seems weird. Am missing something? Thanks
The language.documents.classifyText method returns a ClassificationCategory object which contains name and confidence. If you only want one of the fields you can filter by categories/name or categories/confidence. As an example I executed:
POST https://language.googleapis.com/v1/documents:classifyText?fields=categories%2Fname&key={YOUR_API_KEY}
{
"document": {
"content": "this is a test for a StackOverflow question. I get an error because I need more words in the document and I don't know what else to say",
"type": "PLAIN_TEXT"
}
}
Which returns:
{
"categories": [
{
"name": "/Science/Computer Science"
},
{
"name": "/Computers & Electronics/Programming"
},
{
"name": "/Jobs & Education"
}
]
}
Direct link to API explorer for interactive testing of my example (change content, filters, etc.)
I'm trying to remove a key from a RethinkDB document.
My approaches (which didn't work):
r.db('db').table('user').replace(function(row){delete row["key"]; return row})
Other approach:
r.db('db').table('user').update({key: null})
This one just sets row.key = null (which looks reasonable).
Examples tested on rethinkdb data explorer through web UI.
Here's the relevant example from the documentation on RethinkDB's website: http://rethinkdb.com/docs/cookbook/python/#removing-a-field-from-a-document
To remove a field from all documents in a table, you need to use replace to update the document to not include the desired field (using without):
r.db('db').table('user').replace(r.row.without('key'))
To remove the field from one specific document in the table:
r.db('db').table('user').get('id').replace(r.row.without('key'))
You can change the selection of documents to update by using any of the selectors in the API (http://rethinkdb.com/api/), e.g. db, table, get, get_all, between, filter.
You can use replace with without:
r.db('db').table('user').replace(r.row.without('key'))
You do not need to use replace to update the entire document.
Here is the relevant documentation: ReQL command: literal
Assume your user document looks like this:
{
"id": 1,
"name": "Alice",
"data": {
"age": 19,
"city": "Dallas",
"job": "Engineer"
}
}
And you want to remove age from the data property. Normally, update will just merge your new data with the old data. r.literal can be used to treat the data object as a single unit.
r.table('users').get(1).update({ data: r.literal({ age: 19, job: 'Engineer' }) }).run(conn, callback)
// Result passed to callback
{
"id": 1,
"name": "Alice",
"data": {
"age": 19,
"job": "Engineer"
}
}
or
r.table('users').get(1).update({ data: { city: r.literal() } }).run(conn, callback)
// Result passed to callback
{
"id": 1,
"name": "Alice",
"data": {
"age": 19,
"job": "Engineer"
}
}
I am developing a web app using Codeigniter and MongoDB.
In the database I got a document that look like this:
{
"_id": {
"$id": "4f609932615a935c18r000000"
},
"basic": {
"name": "The project"
},
"members": [
{
"user_name": "john",
"role": "user",
"created_at": {
"sec": 1331730738,
"usec": 810000
}
},
{
"user_name": "markus",
"role": "user",
"created_at": {
"sec": 1331730738,
"usec": 810000
}
}
]
}
I need to search this document using both user_name and role. Right now when I am using the below code I get both. I only want to get array items matching both user_name and role.
$where = array (
'_id' => new MongoId ($account_id),
'members.user_id' => new MongoId ($user_id),
'members.role' => $role
);
$this -> cimongo -> where ($where) -> count_all_results ('accounts');
This is an old question, but as of MongoDB 2.2 or so you can use the $ positional operator in a projection so that only the matched array element is included in the result.
So you can do something like this:
$this->cimongo->where($where)->select(array('members.$'))->get('accounts');
This is a repeat of this question:
Get particular element from mongoDB array
Also you might want to use $elemMatch
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanArray
Here is the rub -- you aren't going to be able to get the array items that match because mongo is going to return the entire document if those elements match. You will have to parse out the code client side. Mongo doesn't have a way to answer, "return only the array that matches."