How to update(add/remove) all Groups in ONE Grouping, without affecting OTHER Groupings? - api

I need help with an API call to update a Members Groups in a Grouping in my MailChimp List.
I have a few "Interest Groupings", each with several "Groups". For example, the first two are....
Grouping: Purchased
Groups: P_SPA3ASX, P_SPA3CFD, P_SPA3ETF, .....
Grouping: Member Stattus
Groups: Lead, Active, Inactive, Staff
Using an API call, I would like to update the Groups in the Purchased Grouping, without affecting ANY of the other Groupings. I have had some success but one scenario eludes me.
My API Call looks like this:
POST to: https://us11.api.mailchimp.com/2.0/lists/update-member.json
POST Body is:
{
"apikey": "myapikey",
"id": "mtlistid",
"email": {
"leid": "165320973"
},
"double_optin": false,
"update_existing": false,
"send_welcome": false,
"replace_interests": false,
"merge_vars": {
"groupings": [
{
"name": "Purchased",
"groups": ["P_SPA3ASX","","","",""]
}
]
}
}
When I change the "replace_interests" setting and pass different "groups" to the API, this is what happens.
Scenario 1: replace_interests = false
Result:
Good. Groups are added to "Purchased".
Bad. Groups are NOT removed from "Purchased".
Good. Other Groupings are not affected.
Scenario 2: replace_interests = true
Result:
Good. Groups are added to "Purchased".
Good. Groups are removed from "Purchased".
Bad. Other Groupings ARE affected. They are all cleared!
But how do I achieve all three (Add Groups, Remove Groups and Not affect other Groupings).

This isn't possible via API v2.0. In order to update a list subscribers interests, you have to supply all of them due to the use of an array to describe that data. In API v3.0, interests can be modified individually without affecting other interests.

Related

FaunaDB: Query for all documents not referenced by another collection

I'm working on an app where users learn about different patterns of grammar in a language. There are three collections; users and patterns are interrelated by progress, which looks like this:
Create(Collection("progress"), {
data: {
userRef: Ref(Collection("users"), userId),
patternRef: Ref(Collection("patterns"), patternId),
initiallyLearnedAt: Now(),
lastReviewedAt: Now(),
srsLevel: 1
}
})
I've learned how to do some basic Fauna queries, but now I have a somewhat more complex relational one. I want to write an FQL query (and the required indexes) to retrieve all patterns for which a given user doesn't have progress. That is, everything they haven't learned yet. How would I compose such a query?
One clarifying assumption - a progress document is created when a user starts on a particular pattern and means the user has some progress. For example, if there are ten patterns and a user has started two, there will be two documents for that user in progress.
If that assumption is valid, your question is "how can we find the other eight?"
The basic approach is:
Get all available patterns.
Get the patterns a user has worked on.
Select the difference between the two sets.
1. Get all available patterns.
This one is trivial with the built-in Documents function in FQL:
Documents(Collection("patterns"))
2. Get the patterns a user has worked on.
To get all the patterns a user has worked on, you'll want to create an index over the progress collection, as you've figured out. Your terms are what you want to search on, in this case userRef. Your values are the results you want back, in this case patternRef.
This looks like the following:
CreateIndex({
name: "patterns_by_user",
source: Collection("progress"),
terms: [
{ field: ["data", "userRef"] }
],
values: [
{ field: ["data", "patternRef"] }
],
unique: true
})
Then, to get the set of all the patterns a user has some progress against:
Match(
"patterns_by_user",
Ref(Collections("users"), userId)
)
3. Select the difference between the two sets
The FQL function Difference has the following signature:
Difference( source, diff, ... )
This means you'll want the largest set first, in this case all of the documents from the patterns collection.
If you reverse the arguments you'll get an empty set, because there are no documents in the set of patterns the user has worked on that are not also in the set of all patterns.
From the docs, the return value of Difference is:
When source is a Set Reference, a Set Reference of the items in source that are missing from diff.
This means you'll need to Paginate over the difference to get the references themselves.
Paginate(
Difference(
Documents(Collection("patterns")),
Match(
"patterns_by_user",
Ref(Collection("users"), userId)
)
)
)
From there, you can do what you need to do with the references. As an example, to retrieve all of the data for each returned pattern:
Map(
Paginate(
Difference(
Documents(Collection("patterns")),
Match(
"patterns_by_user",
Ref(Collection("users"), userId)
)
)
),
Lambda("patternRef", Get(Var("patternRef")))
)
Consolidated solution
Create the index patterns_by_user as in step two
Query the difference as in step three

Square Connect API: Retrieving all items within a category

I have been reading over the Square Connect API and messing around with the catalog portion.
I am unable to find how to retrieve all items and their data associated with a particular category. Can someone please point me in the right direction.
I thought it was the
BatchRetrieveCatalogObjects endpoint
I was using the category ID but it was only returning the catalog's data. I need each of the IDs of the items to retrieve their individual data.
I was looking to propagate a list of all the items and their data in one request in JSON.
JSON data to be passed to endpoint:
data = {
"object_ids": [
"category id"
],
"include_related_objects": True
}
My connection to the API:
category_item_endpoint = self.connection.post('/v2/catalog/batch-retrieve', data)
I am using python3 and the requests library.
In order to list items in a category I found it easiest to use the /v2/catalog/search endpoint. Simply follow the documentation on what parameters are accepted. Below are the search parameters that I used to list items by category id.
let sParams: JSON = [
"object_types": [
"ITEM"
],
"include_related_objects": true,
"include_deleted_objects": false,
"query": [
"exact_query": [
"attribute_name": "category_id",
"attribute_value": id
]
],
"limit": 1000
]
You'd probably have the most luck listing your entire catalog GET /v2/catalog/list and then applying filtering (in this case specific catagory_ids ) after you get the data. Based on the documentation doing what you desire doesn't seem possible with an endpoint/query combitionation.

REST API Design: Subcollection inheriting an editable variation of a resource

Bear with me, as I'm new to API Design and stackoverflow.
For my API design I have three main components:
key/value pairs (a singleton resource)
group (a collection of KVPs)
subgroup (a variation of the corresponding group)
In my API the user should be able to:
create, retrieve, update, and delete KVPs (basic CRUD actions)
organize KVPs into groups and access a listing of those groups
create subgroup variations of the groups that automatically inherit the parent groups' KVPs, and in those subgroups they can edit each KVPs data independently
For example, my Create a New Group request in my documentation looks like this:
{
"group": "age",
"kvps" : [
{
"key": "height",
"value": 5.2
}, {
"key": "weight",
"value": 150
}
],
"subgroups": [
"adult",
"teen",
"baby"
]
}
Using this as an example, I would like the subgroups "adult", "teen", and "baby" to have their own versions of the KVPs "height" and "weight" each with a different value (e.g. adult with a height of 6 and weight of 200, teen with a height of 5.2 and weight 140, etc.) that can be edited independently from each other.
My question: How should I structure my api so that a user could either:
have just editable kvps
have any number of editable kvps organized into any number of groups
or
have any number of editable kvps organized into groups and then further into subgroups
WITHOUT duplicating any of the data?
So far I have a uri structure like this:
/settings/kvps/{kvp_id} (CRUD on one single KVP)
/settings/groups/{group_id} (CRUD on one single group)
/settings/groups/{group_id}/kvps/{kvp_id}
/settings/groups/{group_id}/subgroups/{subgroup_id}
/settings/groups/{group_id}/subgroups/{subgroup_id}/kvps/{kvp_id}
So the kvps have 3 possible URIs, which seems messy to me, and from what I know editing the value of a kvp at
/settings/groups/1/subgroups/1/kvps/1
would also change its value at
/settings/groups/1/subgroups/2/kvps/1
/settings/groups/1/subgroups/3/kvps/1
/settings/groups/1/kvps/1
/settings/kvps/1
and so on, which is the opposite of what I want.
Any ideas?
Once again, I apologize if this is a very simple question that I am way off of, this is my first time designing an API.

Creating Mandatory User Filters with multiple element IDs

Mandatory User Filters
I am working on a tool to allow customers to apply Mandatory User Filters. When attributes are loaded like "Year" or "Age", each can have hundreds of elements with the subsequent ids. In the POST request to create a filter (documented here: https://developer.gooddata.com/article/lets-get-started-with-mandatory-user-filters), looks like this:
{
"userFilter": {
"content": {
"expression": "[/gdc/md/{project-id}/obj/{object-id}]=[/gdc/md/{project-id}/obj/{object-id}/elements?id={element-id}]"
},
"meta": {
"category": "userFilter",
"title": "My User Filter Name"
}
}
}
In the "expression" property, it notes how one ID could be set. What I want is to have multiple ids associated with the object-id set with the post. For example, if I user wanted to add a filter to all of the elements in "Year" (there are 150) in the demo project, it seems odd to make 150 post requests.
Is there a better way?
UPDATE
Tomas thank you for your help.
I am not having trouble assigning multiple userfilters to a user. I can easily apply a singular filter to a user with the method outlined in the documentation. However, this overwrites the userfilter field. What is the syntax for this?
Here is my demo POST data:
{ "userFilters":
{ "items": [
{ "user": "/gdc/account/profile/decd0b2e3077cf9c47f8cfbc32f6460e",
"userFilters":["/gdc/md/a1nc4jfa14wey1bnfs1vh9dljaf8ejuq/obj/808728","/gdc/md/a1nc4jfa14wey1bnfs1vh9dljaf8ejuq/obj/808729","/gdc/md/a1nc4jfa14wey1bnfs1vh9dljaf8ejuq/obj/808728"]
}
]
}
}
This receives a BAD REQUEST.
I'm not sure what you mean by "have multiple ids associated with the object-id" exactly, but I'll try to tell you all I know about it. :-)
If you indeed made multiple POST requests, created multiple userFilters and set them all for one user, the user wouldn't see anything at all. That's because the system combines separate userFilters using logical AND, and a Year cannot be 2013 and 2014 at the same time. So for the rest of my answer, I'll assume that you want OR instead.
There are several ways to do this. As you may have guessed by now, you can use AND/OR explicitly, using an expression like this:
[/…/obj/{object-id}]=[/…/obj/{object-id}/elements?id={element-id}] OR [/…/obj/{object-id}]=[/…/obj/{object-id}/elements?id={element-id}]
This can often be further simplified to:
[/…/obj/{object-id}] IN ( [/…/obj/{object-id}/elements?id={element-id}], [/…/obj/{object-id}/elements?id={element-id}], … )
If the attribute is a date (year, month, …) attribute, you could, in theory, also specify ranges using BETWEEN instead of listing all elements:
[/…/obj/{object-id}] BETWEEN [/…/obj/{object-id}/elements?id={element-id}] AND [/…/obj/{object-id}/elements?id={element-id}]
It seems, though, that this only works in metrics MAQL and is not allowed in the implementation of user filters. I have no idea why.
Also, for your own attribute like Age, you can't do that since user-defined numeric attributes aren't supported. You could, in theory, add a fact that holds the numeric value, and construct a BETWEEN filter based on that fact. It seems that this is not allowed in the implementation of user filters either. :-(
Hope this helps.

How do I return filtering meta data in a REST API search query

I'm currently designing and implementing a RESTful API in PHP.
The API allows users to search for hotels.
A simplified example of the search request is:
GET hotels/searchresults?location=<location> #collection of hotels within location
The response also contains some meta information about the returned collection.
The basic structure of the response is:
“meta": {
“totalNrOfHotels": 100,
"totalNrAvailable": 80
},
“hotels": [
{
“id": 123,
“name": "Hotel A"
},
{
“id": 135,
“name": "Hotel B"
},
...
]
This resource also supports pagination:
GET hotels/searchresults?location=<location>&offset=0&limit=20
Now, there are a few filters that can be applied to the search results, e.g. stars, rating score.
For example, if I want just 2 star hotels, I can query:
GET hotels/searchresults?location=<location>&offset=0&limit=20&stars=2
Now, in the user interface for filtering, it is common to display the number of options available per filter setting:
In my opinion, these numbers can be seen as meta data about the search query. So, we could add an extra field to the meta in the response:
“meta": {
“totalNrOfHotels": 100,
"totalNrAvailable": 80
“filterNrs": {
"stars”: {
“1": 1,
“2”: 9,
“3”: 39,
“4”: 12,
“5”: 11,
“none”: 9
}
}
},
“hotels": [
{“id": 123,
“name": "Hotel A"
},
{“id": 135,
“name": "Hotel B"
},
...
]
So, I have two questions:
Should this “filterNrs” property sit in the meta section, as proposed above? To me, it doesn’t make sense to be a separate resource/request
How can we deal with the fact that this can slow down the query? I’d prefer to make the “filterNrs” field optional. We are thinking of using a “metaFields" parameter to allow the user to specify which fields in the meta she would like to recieve. We already support this for the hotels returned, with a “fields” parameter. (Similar to: https://developers.google.com/youtube/2.0/developers_guide_protocol_partial). Alternatively, we put this field filterNrs (or the full meta info) in a separate resource, something like hotels/searchresults/meta. From a developers perspective would you prefer to have this split into multiple resources or have a single resource with the option to show full or partial meta information?
Does the number rated per star count varies? For example, do I get different "filterNrs" for the queries below?
GET hotels/searchresults?location=1
GET hotels/searchresults?location=2
I would expect such filters to be contextual, so different locations would return different numbers per star count, which indicates this is some form of contextual information related to the query.
Otherwise if the results are global this indicates it's a separate resource. If it's a separate resource scenario, you can use links to access the numbers and other details about it:
“meta": {
“totalNrOfHotels": 100,
"totalNrAvailable": 80
“filterNrs": {
"stars”: {
"options" : ["1", "2", "3", "4", "5", "none"],
"details" : "http://example.com/stars"
}
}
},