// Feed with no extra fields, of feed group "user"
let feed = client.feed(group: "user", id: "john")
try await feed.getOrCreate()
// More options
let query = FeedQuery(
group: "user",
id: "jack",
data: .init(
description: "My personal feed",
name: "jack",
visibility: "public"
)
)
let feed2 = client.feed(for: query)
try await feed.getOrCreate()Feeds
Creating a Feed
When using server-side SDKs, the user_id parameter is required in the getOrCreate request. It’s needed in order to automatically create a user. Client-side SDKs do not require this parameter as the user is authenticated via token.
// Feed with no extra fields, of feed group "user"
val feed = client.feed(group = "user", id = "john")
feed.getOrCreate()
// More options
val query = FeedQuery(
group = "user",
id = "jack",
data = FeedInputData(
description = "My personal feed",
name = "jack",
visibility = FeedVisibility.Public
)
)
val feed2 = client.feed(query = query)
feed2.getOrCreate()// Feed with no extra fields, of feed group "user"
const feed = client.feed("user", "jack");
await feed.getOrCreate();
// Subscribe to WebSocket events for state updates
await feed.getOrCreate({ watch: true });
// More options
const feed = client.feed("user", "jack");
await feed.getOrCreate({
data: {
description: "My personal feed",
name: "jack",
visibility: "public",
},
});// Feed with no extra fields, of feed group "user"
final feed = client.feed(group: 'user', id: 'john');
await feed.getOrCreate();
// More options
const query = FeedQuery(
fid: FeedId(group: 'user', id: 'jack'),
data: FeedInputData(
description: 'My personal feed',
name: 'jack',
visibility: FeedVisibility.public,
),
);
final feed2 = client.feedFromQuery(query);
await feed2.getOrCreate();// Feed with no extra fields, of feed group "user"
const feed = client.feeds.feed("user", "jack");
await feed.getOrCreate({
// The owner of the feed
user_id: "<user id>",
});
// More options
const feed = client.feeds.feed("user", "jack");
await feed.getOrCreate({
data: {
description: "My personal feed",
name: "jack",
visibility: "public",
},
// The owner of the feed
user_id: "<user id>",
});// Example 1
response, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{
UserID: getstream.PtrTo("john"),
})
if err != nil {
log.Fatal("Error:", err)
}
log.Printf("Success: %+v\n", response)
// Example 2
response2, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{
UserID: getstream.PtrTo("john"),
Data: &getstream.FeedInput{
Description: getstream.PtrTo("My personal feed"),
Name: getstream.PtrTo("John Hikes"),
Visibility: getstream.PtrTo("public"),
}})
if err != nil {
log.Fatal("Error creating advanced feed:", err)
}
log.Printf("Success: %+v\n", response2)testFeed = new Feed("user", testUserId, feeds);
testFeed2 = new Feed("user", testUserId2, feeds);
GetOrCreateFeedRequest feedRequest1 =
GetOrCreateFeedRequest.builder().userID(testUserId).build();
GetOrCreateFeedRequest feedRequest2 =
GetOrCreateFeedRequest.builder().userID(testUserId2).build();
GetOrCreateFeedResponse feedResponse1 = testFeed.getOrCreate(feedRequest1).getData();
GetOrCreateFeedResponse feedResponse2 = testFeed2.getOrCreate(feedRequest2).getData();
testFeedId = feedResponse1.getFeed().getFeed();
testFeedId2 = feedResponse2.getFeed().getFeed();$feed = $feedsClient->feed('user', 'john');
$feedResponse = $feed->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: 'john')
);
// More options
$feed2 = $feedsClient->feed('user', 'jack');
$feedResponse2 = $feed2->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(
userID: 'jack',
data: new GeneratedModels\FeedInput(
description: 'My personal feed',
name: 'jack',
visibility: 'public'
)
)
);var feedResponse1 = await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: _testFeedId,
request: new GetOrCreateFeedRequest { UserID = _testUserId }
);
var feedResponse2 = await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: _testFeedId2,
request: new GetOrCreateFeedRequest { UserID = _testUserId2 }
);feed_response_1 = self.test_feed.get_or_create(user_id=self.test_user_id)
feed_response_2 = self.test_feed_2.get_or_create(
user_id=self.test_user_id_2
)require 'getstream_ruby'
# Feed with no extra fields, of feed group "user"
feed = client.feed('user', 'john')
request = GetStream::Generated::Models::GetOrCreateFeedRequest.new(user_id: 'john')
feed_response = feed.get_or_create_feed(request)
# More options with custom data
feed2 = client.feed('user', 'jack')
request2 = GetStream::Generated::Models::GetOrCreateFeedRequest.new(
user_id: 'jack',
data: GetStream::Generated::Models::FeedInput.new(
description: 'My personal feed',
name: 'jack',
visibility: 'public'
)
)
feed_response2 = feed2.get_or_create_feed(request2)Built-in feed groups
| Group | Description |
|---|---|
user | A feed setup for the content a user creates. Typically you add activities here when someone writes a post |
timeline | The timeline feed is used when you’re following. So if user Charlie is following John, timeline:charlie would follow user:john |
foryou | A version of the timeline feed that adds popular content, and priorities popularity over recency |
notification | A notification feed. Think of the bell icon you see in most apps |
story | A feed set up for users to post story activities (activities with expiration data) |
stories | A timeline feed which can be used to follow other users’ stories. |
Reading a Feed
Here is a basic example of how to read a feed:
let feed = client.feed(group: "user", id: "john")
try await feed.getOrCreate()
let feedData = feed.state.feed
let activities = feed.state.activities
let members = feed.state.membersval feed = client.feed(group = "user", id = "john")
feed.getOrCreate()
val feedData = feed.state.feed
val activities = feed.state.activities
val members = feed.state.membersconst feed = client.feed("user", "john");
await feed.getOrCreate({ watch: true });
const currentState = feed.state.getLatestValue();
const visivility = currentState.visibility;
const name = currentState.name;
const description = currentState.description;
const activities = currentState.activities;
const members = currentState.members;
// Or subscribe to state changes
const unsubscribe = feed.state.subscribe((state) => {
// Called everytime the state changes
console.log(state);
});
// or if you care only part of the state
const unsubscribe2 = feed.state.subscribeWithSelector(
(state) => ({
activities: state.activities,
}),
(state, prevState) => {
console.log(state.activities, prevState?.activities);
},
);
// Unsubscribe when you no longer want to recieve updates
unsubscribe();
unsubscribe2();final feed = client.feed(group: 'user', id: 'john');
await feed.getOrCreate();
final feedData = feed.state.feed;
final activities = feed.state.activities;
final members = feed.state.members;
// Note: Always dispose the feed when you are done with it
feed.dispose();const feed = client.feed(group: "user", id: "john")
const response = await feed.getOrCreate({
user_id: '<user id>'
})
const feedData = response.feed;
const activities = response.activities;
const members = response.members;feed := client.Feeds().Feed("user", "john")
response, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{
UserID: getstream.PtrTo("john"),
})
if err != nil {
log.Fatal("Error calling getOrCreate:", err)
}
feedData := response.Data.Feed
activities := response.Data.Activities
members := response.Data.MemberstestFeed = new Feed("user", testUserId, feeds);
GetOrCreateFeedRequest feedRequest1 =
GetOrCreateFeedRequest.builder().userID(testUserId).build();
GetOrCreateFeedResponse feedResponse1 = testFeed.getOrCreate(feedRequest1).getData();
testFeedId = feedResponse1.getFeed().getFeed();$feed = $feedsClient->feed('user', 'john');
$response = $feed->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: 'john')
);
// Access feed data
$feedData = $response->getData()->feed;
$activities = $response->getData()->activities;
$members = $response->getData()->members;var feedResponse1 = await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: _testFeedId,
request: new GetOrCreateFeedRequest { UserID = _testUserId }
);feed_response_1 = self.test_feed.get_or_create(user_id=self.test_user_id)require 'getstream_ruby'
# Reading a feed
feed = client.feed('user', 'john')
request = GetStream::Generated::Models::GetOrCreateFeedRequest.new(user_id: 'john')
feed_response = feed.get_or_create_feed(request)
# Access feed data
feed_data = feed_response.feed
activities = feed_response.activities
members = feed_response.membersThe response will contain the following data.
You have more options when reading a feed, let’s go over a few:
let query = FeedQuery(
group: "user",
id: "john",
activityFilter: .in(.filterTags, ["green"]), // filter activities with filter tag green
activityLimit: 10,
externalRanking: ["user_score": 0.8], // additional data used for ranking
followerLimit: 10,
followingLimit: 10,
memberLimit: 10,
view: "myview", // overwrite the default ranking or aggregation logic for this feed. good for split testing
watch: true // receive web-socket events with real-time updates
)
let feed = client.feed(for: query)
try await feed.getOrCreate()
let activities = feed.state.activities
let feedData = feed.state.feedval query = FeedQuery(
group = "user",
id = "john",
activityFilter = ActivitiesFilterField.filterTags.`in`("green"), // filter activities with filter tag green
activityLimit = 10,
externalRanking = mapOf("user_score" to 0.8), // additional data used for ranking
followerLimit = 10,
followingLimit = 10,
memberLimit = 10,
view = "myview", // overwrite the default ranking or aggregation logic for this feed. good for split testing
watch = true // receive web-socket events with real-time updates
)
val feed = client.feed(query = query)
feed.getOrCreate()
val activities = feed.state.activities
val feedData = feed.state.feedconst feed = client.feed("user", "jack");
const response = await feed.getOrCreate({
limit: 10,
filter: {
filter_tags: ["green"], // filter activities with filter tag green
},
external_ranking: {
user_score: 0.8, // additional data used for ranking
},
followers_pagination: {
limit: 10,
},
following_pagination: {
limit: 10,
},
member_pagination: {
limit: 10,
},
view: "myview", // overwrite the default ranking or aggregation logic for this feed. good for split testing
});const query = FeedQuery(
fid: FeedId(group: 'user', id: 'john'),
// filter activities with filter tag green
activityFilter: Filter.in_(
ActivitiesFilterField.filterTags,
['green'],
),
activityLimit: 10,
// additional data used for ranking
externalRanking: {'user_score': 0.8},
followerLimit: 10,
followingLimit: 10,
memberLimit: 10,
// overwrite the default ranking or aggregation logic for this feed. good for split testing
view: 'myview',
// receive web-socket events with real-time updates
watch: true,
);
final feed = client.feedFromQuery(query);
await feed.getOrCreate();
final activities = feed.state.activities;
final feedData = feed.state.feed;
// Note: Always dispose the feed when you are done with it
feed.dispose();const feed = client.feeds.feed("user", "jack");
const response = await feed.getOrCreate({
limit: 10,
filter: {
filter_tags: ["green"], // filter activities with filter tag green
},
external_ranking: {
user_score: 0.8, // additional data used for ranking
},
followers_pagination: {
limit: 10,
},
following_pagination: {
limit: 10,
},
member_pagination: {
limit: 10,
},
view: "myview", // overwrite the default ranking or aggregation logic for this feed. good for split testing
user_id: "<user id>",
});feed := client.Feeds().Feed("user", "jack")
request := &getstream.GetOrCreateFeedRequest{
Limit: intPtr(10),
UserID: stringPtr("<user id>"),
View: stringPtr("myview"),
Filter: map[string]any{
"filter_tags": []string{"green"}, // filter activities with filter tag green
},
ExternalRanking: map[string]any{
"user_score": 0.8, // additional data used for ranking
},
FollowersPagination: &getstream.PagerRequest{
Limit: intPtr(10),
},
FollowingPagination: &getstream.PagerRequest{
Limit: intPtr(10),
},
MemberPagination: &getstream.PagerRequest{
Limit: intPtr(10),
},
}
response, err := feed.GetOrCreate(context.Background(), request)testFeed = new Feed("user", testUserId, feeds);
testFeed2 = new Feed("user", testUserId2, feeds);
GetOrCreateFeedRequest feedRequest1 =
GetOrCreateFeedRequest.builder().userID(testUserId).build();
GetOrCreateFeedRequest feedRequest2 =
GetOrCreateFeedRequest.builder().userID(testUserId2).build();
GetOrCreateFeedResponse feedResponse1 = testFeed.getOrCreate(feedRequest1).getData();
GetOrCreateFeedResponse feedResponse2 = testFeed2.getOrCreate(feedRequest2).getData();
testFeedId = feedResponse1.getFeed().getFeed();
testFeedId2 = feedResponse2.getFeed().getFeed();$feed = $feedsClient->feed('user', 'jack');
$response = $feed->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(
limit: 10,
filter: (object)['filter_tags' => ['green']],
externalRanking: (object)['user_score' => 0.8],
followersPagination: new GeneratedModels\PagerRequest(limit: 10),
followingPagination: new GeneratedModels\PagerRequest(limit: 10),
memberPagination: new GeneratedModels\PagerRequest(limit: 10),
view: 'myview',
userID: 'jack'
)
);var feedResponse1 = await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: _testFeedId,
request: new GetOrCreateFeedRequest { UserID = _testUserId }
);
var feedResponse2 = await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: _testFeedId2,
request: new GetOrCreateFeedRequest { UserID = _testUserId2 }
);feed_response_1 = self.test_feed.get_or_create(user_id=self.test_user_id)
feed_response_2 = self.test_feed_2.get_or_create(
user_id=self.test_user_id_2
)require 'getstream_ruby'
# Reading multiple feeds
feed1 = client.feed('user', 'john')
request1 = GetStream::Generated::Models::GetOrCreateFeedRequest.new(user_id: 'john')
feed_response_1 = feed1.get_or_create_feed(request1)
feed2 = client.feed('user', 'jane')
request2 = GetStream::Generated::Models::GetOrCreateFeedRequest.new(user_id: 'jane')
feed_response_2 = feed2.get_or_create_feed(request2)Feed Pagination
Here is how you can read the next page on the feed:
let feed = client.feed(
for: .init(
group: "user",
id: "john",
activityLimit: 10
)
)
// Page 1
try await feed.getOrCreate()
let activities = feed.state.activities // First 10 activities
// Page 2
let page2Activities = try await feed.queryMoreActivities(limit: 10)
let page1And2Activities = feed.state.activitiesval feed = client.feed(
query = FeedQuery(
group = "user",
id = "john",
activityLimit = 10
)
)
// Page 1
feed.getOrCreate()
val activities = feed.state.activities // First 10 activities
// Page 2
val page2Activities: Result<List<ActivityData>> = feed.queryMoreActivities(limit = 10)
val page1And2Activities = feed.state.activitiesconst feed = client.feed("user", "jack");
// First page
await feed.getOrCreate({
limit: 10,
});
// Second page
await feed.getNextPage();
console.log(feed.state.getLatestValue().activities);
// Only if feed group has aggregation turned on
console.log(feed.state.getLatestValue().aggregated_activities);final feed = client.feedFromQuery(
const FeedQuery(
fid: FeedId(group: 'user', id: 'john'),
activityLimit: 10,
),
);
// Page 1
await feed.getOrCreate();
final activities = feed.state.activities; // First 10 activities
// Page 2
final page2Activities = await feed.queryMoreActivities(limit: 10);
final page1And2Activities = feed.state.activities;const feed = client.feeds.feed("user", "jack");
const firstPage = await feed.getOrCreate({
limit: 10,
user_id: "user_id",
});
const nextPage = await feed.getOrCreate({
next: firstPage.next,
limit: 10,
user_id: "user_id",
});feed := client.Feeds().Feed("user", "john")
// First page
firstPage, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{
Limit: getstream.PtrTo(10),
UserID: getstream.PtrTo("john"),
})
if err != nil {
log.Fatal("Error getting first page:", err)
}
// Second page request using next cursor
nextPage, err := feed.GetOrCreate(context.Background(), &getstream.GetOrCreateFeedRequest{
Next: firstPage.Data.Next,
Limit: getstream.PtrTo(10),
UserID: getstream.PtrTo("john"),
})
if err != nil {
log.Fatal("Error getting next page:", err)
}
log.Printf("First page activities count: %d", len(firstPage.Data.Activities))
log.Printf("Next page activities count: %d", len(nextPage.Data.Activities))testFeed = new Feed("user", testUserId, feeds);
testFeed2 = new Feed("user", testUserId2, feeds);
GetOrCreateFeedRequest feedRequest1 =
GetOrCreateFeedRequest.builder().userID(testUserId).build();
GetOrCreateFeedRequest feedRequest2 =
GetOrCreateFeedRequest.builder().userID(testUserId2).build();
GetOrCreateFeedResponse feedResponse1 = testFeed.getOrCreate(feedRequest1).getData();
GetOrCreateFeedResponse feedResponse2 = testFeed2.getOrCreate(feedRequest2).getData();
testFeedId = feedResponse1.getFeed().getFeed();
testFeedId2 = feedResponse2.getFeed().getFeed();$feed = $feedsClient->feed('user', 'jack');
$feedResponse1 = $feed->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: "jack", limit: 10)
);
$feedResponse2 = $feed->getOrCreateFeed(
new GeneratedModels\GetOrCreateFeedRequest(userID: "jack", limit: 10, next: $feedResponse1->getData()->next)
);var feedResponse1 = await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: _testFeedId,
request: new GetOrCreateFeedRequest { UserID = _testUserId }
);
var feedResponse2 = await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: _testFeedId2,
request: new GetOrCreateFeedRequest { UserID = _testUserId2 }
);feed_response_1 = self.test_feed.get_or_create(user_id=self.test_user_id)
feed_response_2 = self.test_feed_2.get_or_create(
user_id=self.test_user_id_2
)Filters
filter provides a performant way to read a feed, and only select activities that match a given filter.
Please note that filtering is typically used for fields with fixed value sets (for example filter_tags), for text based search, you should check out query activities endpoint
Examples
// Add a few activities
let feedId = FeedId(group: "user", id: "john")
try await client.upsertActivities([
ActivityRequest(feeds: [feedId.rawValue], filterTags: ["green", "blue"], text: "first", type: "post"),
ActivityRequest(feeds: [feedId.rawValue], filterTags: ["yellow", "blue"], text: "second", type: "post"),
ActivityRequest(feeds: [feedId.rawValue], filterTags: ["orange"], text: "third", type: "post")
])
// Now read the feed, this will fetch activity 1 and 2
let query = FeedQuery(feed: feedId, activityFilter: .in(.filterTags, ["blue"]))
let feed = client.feed(for: query)
try await feed.getOrCreate()
let activities = feed.state.activities // contains first and second// Add a few activities
val fid = FeedId(group = "user", id = "john")
client.upsertActivities(
listOf(
ActivityRequest(feeds = listOf(fid.rawValue), filterTags = listOf("green", "blue"), text = "first", type = "post"),
ActivityRequest(feeds = listOf(fid.rawValue), filterTags = listOf("yellow", "blue"), text = "second", type = "post"),
ActivityRequest(feeds = listOf(fid.rawValue), filterTags = listOf("orange"), text = "third", type = "post")
)
)
// Now read the feed, this will fetch activity 1 and 2
val query = FeedQuery(fid = fid, activityFilter = ActivitiesFilterField.filterTags.`in`("blue"))
val feed = client.feed(query = query)
feed.getOrCreate()
val activities = feed.state.activities // contains first and secondconst feed = client.feed("user", "123", {
// WebSocket events are delivered regardless of filters, you can filter them by providing activityAddedEventFilter
activityAddedEventFilter: (event) =>
event.activity.filter_tags.includes("blue"),
});
// Add a few activities
client.upsertActivities({
activities: [
{
feeds: [feed.feed],
type: "post",
text: "first",
filter_tags: ["green", "blue"],
},
{
feeds: [feed.feed],
type: "post",
text: "second",
filter_tags: ["yellow", "blue"],
},
{
feeds: [feed.feed],
type: "post",
text: "third",
filter_tags: ["orange"],
},
],
});
const response = await feed.getOrCreate({
watch: true,
filter: {
filter_tags: ["blue"],
},
});// Add a few activities
const feedId = FeedId(group: 'user', id: 'john');
await client.upsertActivities(
activities: [
ActivityRequest(
feeds: [feedId.rawValue],
filterTags: const ['green', 'blue'],
text: 'first',
type: 'post',
),
ActivityRequest(
feeds: [feedId.rawValue],
filterTags: const ['yellow', 'blue'],
text: 'second',
type: 'post',
),
ActivityRequest(
feeds: [feedId.rawValue],
filterTags: const ['orange'],
text: 'third',
type: 'post',
),
],
);
// Now read the feed, this will fetch activity 1 and 2
const query = FeedQuery(
fid: feedId,
activityFilter: Filter.in_(ActivitiesFilterField.filterTags, ['blue']),
);
final feed = client.feedFromQuery(query);
await feed.getOrCreate();
// contains first and second
final activities = feed.state.activities;const feed = client.feeds.feed("user", "123");
// Add a few activities
client.feeds.upsertActivities({
activities: [
{
feeds: [feed.feed],
type: "post",
text: "first",
filter_tags: ["green", "blue"],
user_id: "<user id>",
},
{
feeds: [feed.feed],
type: "post",
text: "second",
filter_tags: ["yellow", "blue"],
user_id: "<user id>",
},
{
feeds: [feed.feed],
type: "post",
text: "third",
filter_tags: ["orange"],
user_id: "<user id>",
},
],
});
const response = await feed.getOrCreate({
filter: {
filter_tags: ["blue"],
},
user_id: "<user id>",
});ctx := context.Background()
// Create feed
feed := client.Feeds().Feed("user", "john")
// Create activities
activities := []getstream.ActivityRequest{
{
Feeds: []string{"user:john"},
Type: "post",
Text: stringPtr("first"),
FilterTags: []string{"green", "blue"},
UserID: stringPtr("john"),
},
{
Feeds: []string{"user:john"},
Type: "post",
Text: stringPtr("second"),
FilterTags: []string{"yellow", "blue"},
UserID: stringPtr("john"),
},
{
Feeds: []string{"user:john"},
Type: "post",
Text: stringPtr("third"),
FilterTags: []string{"orange"},
UserID: stringPtr("john"),
},
}
// Upsert activities
_, err = client.Feeds().UpsertActivities(ctx, &getstream.UpsertActivitiesRequest{
Activities: activities,
})
if err != nil {
log.Fatal("Error upserting activities:", err)
}
// Get or create feed with filter
response, err := feed.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
Filter: map[string]any{
"filter_tags": []string{"blue"},
},
UserID: stringPtr("john"),
})
if err != nil {
log.Fatal("Error getting or creating feed:", err)
}
log.Printf("Feed response: %+v", len(response.Data.Activities))// Add a few activities
List<ActivityRequest> activities = List.of(
ActivityRequest.builder()
.feeds(List.of("user:123"))
.type("post")
.text("first")
.filterTags(List.of("green", "blue"))
.userID("123")
.build(),
ActivityRequest.builder()
.feeds(List.of("user:123"))
.type("post")
.text("second")
.filterTags(List.of("yellow", "blue"))
.userID("123")
.build(),
ActivityRequest.builder()
.feeds(List.of("user:123"))
.type("post")
.text("third")
.filterTags(List.of("orange"))
.userID("123")
.build()
);
feeds.upsertActivities(
UpsertActivitiesRequest.builder()
.activities(activities)
.build()
).execute();
// Now read the feed, this will fetch activity 1 and 2
Map<String, Object> filter = new HashMap<>();
filter.put("filter_tags", List.of("blue"));
GetOrCreateFeedRequest feedRequest = GetOrCreateFeedRequest.builder()
.filter(filter)
.userID("123")
.build();
GetOrCreateFeedResponse response = feeds.getOrCreateFeed("user", "123", feedRequest).execute().getData();$feed = $feedsClient->feed('user', '123');
// Add a few activities
$feedsClient->upsertActivities(
new GeneratedModels\UpsertActivitiesRequest(
activities: [
[
'feeds' => [$feed->getFeedIdentifier()],
'type' => 'post',
'text' => 'first',
'filter_tags' => ['green', 'blue'],
'user_id' => '123',
],
[
'feeds' => [$feed->getFeedIdentifier()],
'type' => 'post',
'text' => 'second',
'filter_tags' => ['yellow', 'blue'],
'user_id' => '123',
],
[
'feeds' => [$feed->getFeedIdentifier()],
'type' => 'post',
'text' => 'third',
'filter_tags' => ['orange'],
'user_id' => '123',
],
]
)
);
// Now read the feed, this will fetch activity 1 and 2
$response = $feedsClient->getOrCreateFeed(
'user',
'123',
new GeneratedModels\GetOrCreateFeedRequest(
filter: (object)['filter_tags' => ['blue']],
userID: '123'
)
);// Add a few activities
await _feedsV3Client.UpsertActivitiesAsync(
request: new UpsertActivitiesRequest
{
Activities = new List<ActivityRequest>
{
new ActivityRequest
{
Feeds = new List<string> { "user:123" },
Type = "post",
Text = "first",
FilterTags = new List<string> { "green", "blue" },
UserID = "123"
},
new ActivityRequest
{
Feeds = new List<string> { "user:123" },
Type = "post",
Text = "second",
FilterTags = new List<string> { "yellow", "blue" },
UserID = "123"
},
new ActivityRequest
{
Feeds = new List<string> { "user:123" },
Type = "post",
Text = "third",
FilterTags = new List<string> { "orange" },
UserID = "123"
}
}
}
);
// Now read the feed, this will fetch activity 1 and 2
var response = await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: "123",
request: new GetOrCreateFeedRequest
{
Filter = new { filter_tags = new[] { "blue" } },
UserID = "123"
}
);# Add a few activities
feeds.upsert_activities(
activities=[
{
"feeds": ["user:123"],
"type": "post",
"text": "first",
"filter_tags": ["green", "blue"],
"user_id": "123"
},
{
"feeds": ["user:123"],
"type": "post",
"text": "second",
"filter_tags": ["yellow", "blue"],
"user_id": "123"
},
{
"feeds": ["user:123"],
"type": "post",
"text": "third",
"filter_tags": ["orange"],
"user_id": "123"
}
]
)
# Now read the feed, this will fetch activity 1 and 2
response = feeds.get_or_create_feed(
feed_group="user",
feed_id="123",
filter={"filter_tags": ["blue"]},
user_id="123"
)# Add a few activities
client.feeds.upsert_activities(
GetStream::Generated::Models::UpsertActivitiesRequest.new(
activities: [
{
"feeds" => ["user:123"],
"type" => "post",
"text" => "first",
"filter_tags" => ["green", "blue"],
"user_id" => "123"
},
{
"feeds" => ["user:123"],
"type" => "post",
"text" => "second",
"filter_tags" => ["yellow", "blue"],
"user_id" => "123"
},
{
"feeds" => ["user:123"],
"type" => "post",
"text" => "third",
"filter_tags" => ["orange"],
"user_id" => "123"
}
]
)
)
# Now read the feed, this will fetch activity 1 and 2
response = client.feeds.get_or_create_feed(
"user",
"123",
GetStream::Generated::Models::GetOrCreateFeedRequest.new(
filter: { "filter_tags" => ["blue"] },
user_id: "123"
)
)The filter syntax also supports $or and $and, so here’s an example that’s a little more complicated:
// Get all the activities where filter tags contain both "green" and "orange"
let query = FeedQuery(
group: "user",
id: "john",
activityFilter: .and([
.in(.filterTags, ["green"]),
.in(.filterTags, ["orange"])
])
)
try await feed.getOrCreate()
let activities = feed.state.activities// Get all the activities where filter tags contain both "green" and "orange"
val query = FeedQuery(
group = "user",
id = "john",
activityFilter = Filters.and(
ActivitiesFilterField.filterTags.`in`("green"),
ActivitiesFilterField.filterTags.`in`("orange"),
)
)
feed.getOrCreate()
val activities = feed.state.activities// Get all the activities where filter tags contain both "green" and "orange"
const response = await feed.getOrCreate({
filter: {
$and: [{ filter_tags: ["green"] }, { filter_tags: ["orange"] }],
},
});// Get all the activities where filter tags contain both "green" and "orange"
const query = FeedQuery(
fid: FeedId(group: 'user', id: 'john'),
activityFilter: Filter.and([
Filter.in_(ActivitiesFilterField.filterTags, ['green']),
Filter.in_(ActivitiesFilterField.filterTags, ['orange']),
]),
);
final feed = client.feedFromQuery(query);
await feed.getOrCreate();
final activities = feed.state.activities;// Get all the activities where filter tags contain both "green" and "orange"
const response = await feed.getOrCreate({
filter: {
$and: [
{ filter_tags: ["green"] }
{ filter_tags: ["orange"] }
],
},
user_id: "<user id>",
});// Get all the activities where filter tags contain both "green" and "orange"
feed := client.Feeds().Feed("user", "john")
response, err := feed.GetOrCreate(ctx, &getstream.GetOrCreateFeedRequest{
Filter: map[string]any{
"$and": []map[string]any{
{"filter_tags": []string{"green"}},
{"filter_tags": []string{"orange"}},
},
},
UserID: getstream.PtrTo("john"),
})
if err != nil {
log.Fatal("Error getting feed with filter:", err)
}
log.Printf("Activities: %+v", response.Data.Activities)// Get all the activities where filter tags contain both "green" and "orange"
Map<String, Object> filter = new HashMap<>();
List<Map<String, Object>> andConditions = List.of(
Map.of("filter_tags", List.of("green")),
Map.of("filter_tags", List.of("orange"))
);
filter.put("$and", andConditions);
GetOrCreateFeedRequest request = GetOrCreateFeedRequest.builder()
.filter(filter)
.userID("john")
.build();
GetOrCreateFeedResponse response = feeds.getOrCreateFeed("user", "john", request).execute().getData();$response = $feedsClient->getOrCreateFeed(
'user',
'123',
new GeneratedModels\GetOrCreateFeedRequest(
filter: (object)['and' => [
'filter_tags' => ['green'],
'filter_tags' => ['orange'],
]],
userID: '123'
)
);// Get all the activities where filter tags contain both "green" and "orange"
var response = await _feedsV3Client.GetOrCreateFeedAsync(
FeedGroupID: "user",
FeedID: "john",
request: new GetOrCreateFeedRequest
{
Filter = new
{
and = new[]
{
new { filter_tags = new[] { "green" } },
new { filter_tags = new[] { "orange" } }
}
},
UserID = "john"
}
);# Get all the activities where filter tags contain both "green" and "orange"
response = feeds.get_or_create_feed(
feed_group="user",
feed_id="john",
filter={
"$and": [
{"filter_tags": ["green"]},
{"filter_tags": ["orange"]}
]
},
user_id="john"
)# Get all the activities where filter tags contain both "green" and "orange"
response = client.feeds.get_or_create_feed(
"user",
"john",
GetStream::Generated::Models::GetOrCreateFeedRequest.new(
filter: {
"$and" => [
{ "filter_tags" => ["green"] },
{ "filter_tags" => ["orange"] }
]
},
user_id: "john"
)
)Supported filters
What filters you can use when reading a feed depends on the feed group (or view, if provided) configuration.
The activity selectors page explains this in detail, but some quick examples: the user group uses current selector, and the timeline group the following selector by default.
The following filter options are available for the following selector:
| name | type | description | supported operations | example |
|---|---|---|---|---|
id | string or list of strings | The ID of the activity | $in, $eq | { id: { $in: [ 'abc', 'xyz' ] } } |
filter_tags | list of strings | Tags for filtering | $eq, $contains | { filter_tags: { $in: [ 'categoryA', 'categoryB' ] } } |
The following filter options are available for the current, popular, interest, proximity and query selectors:
| name | type | description | supported operations | example |
|---|---|---|---|---|
id | string or list of strings | The ID of the activity | $in, $eq | { id: { $in: [ 'abc', 'xyz' ] } } |
activity_type | string or list of strings | The type of the activity | $in, $eq | { activity_type: { $in: [ 'abc', 'xyz' ] } } |
user_id | string or list of strings | The ID of the user who created the activity | $in, $eq | { user_id: { $in: [ 'abc', 'xyz' ] } } |
text | string | The text content of the activity | $eq, $q, $autocomplete | { text: { $q: 'popularity' } } |
search_data | object | The extra metadata for search indexing | $contains, $path_exists | { search_data: { $contains: { 'category': 'sports', 'status': 'active' } } } |
interest_tags | list of strings | Tags for user interests | $eq, $contains | { interest_tags: { $in: [ 'sports', 'music' ] } } |
filter_tags | list of strings | Tags for filtering | $eq, $contains | { filter_tags: { $in: [ 'categoryA', 'categoryB' ] } } |
created_at | string, must be formatted as an RFC3339 timestamp | The time the activity was created | $eq, $gt, $lt, $gte, $lte | { created_at: { $gte: '2023-12-04T09:30:20.45Z' } } |
popularity | number | The popularity score of the activity | $eq, $ne, $gt, $lt, $gte, $lte | { popularity: { $gte: 70 } } |
near | object | Indicates the GEO point to search nearby activities. | $eq | { near: { $eq: { lat: 40.0, lng: -74.0, distance: 200 } } } |
within_bounds | object | Indicates the GEO bounds to search for activities within. | $eq | { within_bounds: { $eq: { ne_lat: 40.0, ne_lng: -115.0, sw_lat: 32.0, sw_lng: -125.0 } } } |
The filter syntax also supports $or and $and:
// Get all the activities where filter tags contain both "green" and "orange"
let filter = .and([
.in(.filterTags, ["green"]),
.in(.filterTags, ["orange"])
])// Get all the activities where filter tags contain both "green" and "orange"
val filter = Filters.and(
ActivitiesFilterField.filterTags.`in`("green"),
ActivitiesFilterField.filterTags.`in`("orange"),
)// Get all the activities where filter tags contain both "green" and "orange"
const filter = {
$and: [{ filter_tags: ["green"] }, { filter_tags: ["orange"] }],
};// Get all the activities where filter tags contain both "green" and "orange"
const filter = Filter.and([
Filter.in_(ActivitiesFilterField.filterTags, ['green']),
Filter.in_(ActivitiesFilterField.filterTags, ['orange']),
])// Get all the activities where filter tags contain both "green" and "orange"
const filter = {
$and: [
{ filter_tags: ["green"] }
{ filter_tags: ["orange"] }
],
}// Get all the activities where filter tags contain both "green" and "orange"
filter := map[string]any{
"$and": []map[string]any{
{"filter_tags": []string{"green"}},
{"filter_tags": []string{"orange"}},
},
}// Get all the activities where filter tags contain both "green" and "orange"
Map<String, Object> filter = new HashMap<>();
List<Map<String, Object>> andConditions = List.of(
Map.of("filter_tags", List.of("green")),
Map.of("filter_tags", List.of("orange"))
);
filter.put("$and", andConditions);$filter = (object)['and' => [
'filter_tags' => ['green'],
'filter_tags' => ['orange'],
]]// Get all the activities where filter tags contain both "green" and "orange"
var filter = = new
{
and = new[]
{
new { filter_tags = new[] { "green" } },
new { filter_tags = new[] { "orange" } }
}
}# Get all the activities where filter tags contain both "green" and "orange"
filter = {
"$and": [
{"filter_tags": ["green"]},
{"filter_tags": ["orange"]}
]
}# Get all the activities where filter tags contain both "green" and "orange"
filter = {
"$and" => [
{ "filter_tags" => ["green"] },
{ "filter_tags" => ["orange"] }
]
}When providing filter to read a feed, activity selector filters on group/view level are ignored.
Overview of built-in fields
GetOrCreateFeedResponse
| Name | Type | Description | Constraints |
|---|---|---|---|
activities | ActivityResponse[] | - | Required |
aggregated_activities | AggregatedActivityResponse[] | - | Required |
created | boolean | - | Required |
duration | string | Duration of the request in milliseconds | Required |
feed | FeedResponse | - | Required |
followers | FollowResponse[] | - | Required |
followers_pagination | PagerResponse | - | - |
following | FollowResponse[] | - | Required |
following_pagination | PagerResponse | - | - |
member_pagination | PagerResponse | - | - |
members | FeedMemberResponse[] | - | Required |
next | string | - | - |
notification_status | NotificationStatusResponse | - | - |
pinned_activities | ActivityPinResponse[] | - | Required |
prev | string | - | - |
FeedResponse
| Name | Type | Description | Constraints |
|---|---|---|---|
created_at | number | When the feed was created | Required |
created_by | UserResponse | User who created the feed | Required |
custom | object | Custom data for the feed | - |
deleted_at | number | When the feed was deleted | - |
description | string | Description of the feed | Required |
feed | string | Fully qualified feed ID (group_id:id) | Required |
filter_tags | string[] | Tags used for filtering feeds | - |
follower_count | integer | Number of followers of this feed | Required |
following_count | integer | Number of feeds this feed follows | Required |
group_id | string | Group this feed belongs to | Required |
id | string | Unique identifier for the feed | Required |
member_count | integer | Number of members in this feed | Required |
name | string | Name of the feed | Required |
own_capabilities | FeedOwnCapability[] | Capabilities the current user has for this feed | - |
own_follows | FollowResponse[] | Follow relationships where the current user's feeds are following this feed | - |
own_membership | FeedMemberResponse | Membership information for the current user in this feed | - |
pin_count | integer | Number of pinned activities in this feed | Required |
updated_at | number | When the feed was last updated | Required |
visibility | string | Visibility setting for the feed | - |
Deleting a Feed
Deleting a feed is an irreversible operation. This goes for both soft and hard deletes.
Deleting a feed will cascade delete the following entities:
- Follows - any follow relationship this feed is part of will be deleted
- Feed members
- Pinned activities
- Activity marks (read/seen)
- Activities - the following will be deleted for each activity
- Reactions
- Bookmarks
- Comments - the following will be deleted for each comment
- Reactions
The deletion of a feed will be done asynchronously. If the endpoint is called server side a task_id is returned and you
can use this task ID to track the deletion process.
The difference between a hard and soft delete is that soft deleting will soft delete the entities that supports this.
These are feeds, activities and comments. Soft deleted activities will retain their reactions and bookmarks until hard deleted. Soft deleted comments will retain their reactions until hard deleted.
This means that this data can still be exported with the export endpoint.
// Soft delete a feed
try await feed.delete(hardDelete: false)
// Hard delete a feed
try await feed.delete(hardDelete: true)// Soft delete a feed
feed.delete(hardDelete = false)
// Hard delete a feed
feed.delete(hardDelete = true)// Soft delete a feed
await feed.delete({ hard_delete: false });
// Hard delete a feed
await feed.delete({ hard_delete: true });// Soft delete a feed
await feed.delete(hardDelete: false);
// Hard delete a feed
await feed.delete(hardDelete: true);// Soft delete a feed
const response = await feed.delete({ hard_delete: false });
// Hard delete a feed
const response = await feed.delete({ hard_delete: true });
// Check task progress for server side requests (you need to poll getTask)
const taskResponse = await client.getTask({ id: response.task_id });
console.log(taskResponse.status === "completed");// Soft delete a feed
response, err := feed.Delete(context.Background(), &getstream.DeleteFeedRequest{
HardDelete: getstream.PtrTo(false),
})
// Hard delete a feed
response, err := feed.Delete(context.Background(), &getstream.DeleteFeedRequest{
HardDelete: getstream.PtrTo(true),
})
// Check task progress (you need to poll GetTask)
taskResponse, err := client.GetTask(context.Background(), response.Data.TaskID, &getstream.GetTaskRequest{})
fmt.Println(taskResponse.Data.Status == "completed")// Soft delete a feed
DeleteFeedRequest deleteRequest = DeleteFeedRequest.builder()
.hardDelete(false)
.build();
DeleteFeedResponse response = feed.delete(deleteRequest).getData();
// Hard delete a feed
DeleteFeedRequest hardDeleteRequest = DeleteFeedRequest.builder()
.hardDelete(true)
.build();
feed.delete(hardDeleteRequest);
// Check task progress (you need to poll getTask)
GetTaskResponse taskResponse = client.getTask(response.getTaskId()).getData();
System.out.println(taskResponse.getStatus().equals("completed"));// Soft delete a feed
$response = $feed->delete(
new GeneratedModels\DeleteFeedRequest(hardDelete: false)
);
// Hard delete a feed
$response = $feed->delete(
new GeneratedModels\DeleteFeedRequest(hardDelete: true)
);
// Check task progress (you need to poll getTask)
$taskResponse = $client->getTask($response->getData()->taskID);
echo $taskResponse->getData()->status === 'completed';// Soft delete a feed
var response = await feed.DeleteAsync(new DeleteFeedRequest { HardDelete = false });
// Hard delete a feed
await feed.DeleteAsync(new DeleteFeedRequest { HardDelete = true });
// Check task progress (you need to poll GetTaskAsync)
var taskResponse = await client.GetTaskAsync(response.TaskId);
Console.WriteLine(taskResponse.Status == "completed");# Soft delete a feed
response = feed.delete(hard_delete=False)
# Hard delete a feed
response = feed.delete(hard_delete=True)
# Check task progress (you need to poll get_task)
task_response = client.get_task(response.task_id)
print(task_response.status == "completed")require 'getstream_ruby'
# Soft delete a feed
response = feed.delete(hard_delete: false)
# Hard delete a feed
response = feed.delete(hard_delete: true)
# Check task progress (you need to poll get_task)
task_response = client.get_task(response.task_id)
puts task_response.status == 'completed'