// Adding a comment to an activity
let comment = try await feed.addComment(
request: .init(
id: "comment_123", // id is optional, but must be unique. will be auto-generated if not provided
comment: "So great!",
custom: ["sentiment": "positive"],
objectId: "activity_123",
objectType: "activity",
)
)
// Adding a reply to a comment
let reply = try await feed.addComment(
request: .init(
comment: "I agree!",
parentId: "comment_456"
)
)
// Adding a comment with attachments
let commentWithAttachment = try await feed.addComment(
request: .init(
comment: "Check out this image!",
objectId: "activity_123",
objectType: "activity",
attachments: [
Attachment(
imageUrl: "https://example.com/image.jpg",
type: "image"
)
]
)
)Comments
Comments support voting, ranking, threading, images, URL previews, mentions and notifications.
Adding Comments
You can use Stream's CDN for storing and quickly accessing files attached to comments.
Comment request options
Updating Comments
updateComment endpoint performs a partial update: only the fields you include in the request are changed, and each of those fields is completely overwritten.
let response = try await feed.updateComment(
commentId: "comment_123",
request: .init(comment: "Not so great")
)
print("Comment edited at: \(response.comment.editedAt ?? "never")")Removing Comments
try await feed.deleteComment(
commentId: "comment_123"
)Reading Comments
You'll also want to show/return these comments. The most important is when reading the feed.
try await feed.getOrCreate()
print(feed.state.activities[0].comments)
// or
let activity = client.activity(
for: "activity_123",
in: FeedId(group: "user", id: "john")
)
try await activity.get()
print(activity.state.comments)
// Reading a single comment
let comment = try await client.getComment(id: "123")Sort options
The following sort options are supported when reading comments:
last: newest comment returned firstfirst: oldest comment returned firsttop: highest score returned first - computed fromupvote-downvotereaction typescontroversial: controversial comment returned first - mixed reactions (upvoteanddownvote) and lots of commentsbest: highest Wilson score returned first - Wilson score balances reaction score (upvote-downvote) with number of reactions (a comment with lower reaction score but more sum reactions is returned before a comment with higher score, but few sum reactions)
Search for Comments
You can also query the comments, the following examples show
- how to search across all comments by text
- query all comments of a given user
// Search in comment texts
let list1 = client.commentList(
for: .init(
filter: .query(.commentText, "oat")
)
)
let comments1 = try await list1.get()
// Comments from an user
let list2 = client.commentList(
for: .init(
filter: .equal(.userId, "jane")
)
)
let comments2 = try await list2.get()Comment Queryable Built-In Fields
| name | type | description | supported operations | example |
|---|---|---|---|---|
id | string or list of strings | The ID of the comment | $in, $eq | { id: { $in: [ 'comment_123', 'comment_456' ] } } |
user_id | string or list of strings | The ID of the user who created the comment | $in, $eq | { user_id: { $eq: 'user_123' } } |
object_type | string or list of strings | The type of object being commented on | $eq, $ne, $in, $nin | { object_type: { $in: [ 'activity', 'post' ] } } |
object_id | string or list of strings | The ID of the object being commented on | $in, $eq | { object_id: { $eq: 'activity_123' } } |
parent_id | string or list of strings | The parent comment ID for replies | $in, $eq | { parent_id: { $eq: 'comment_parent_123' } } |
comment_text | string | The text content of the comment | $q | { comment_text: { $q: 'search terms' } } |
reply_count | number | The number of replies to this comment | $gt, $gte, $lt, $lte | { reply_count: { $gte: 5 } } |
upvote_count | number | The number of upvotes on the comment | $gt, $gte, $lt, $lte | { upvote_count: { $gte: 10 } } |
downvote_count | number | The number of downvotes on the comment | $gt, $gte, $lt, $lte | { downvote_count: { $lt: 5 } } |
score | number | The overall score of the comment | $gt, $gte, $lt, $lte | { score: { $gte: 0 } } |
confidence_score | number | The confidence score of the comment | $gt, $gte, $lt, $lte | { confidence_score: { $gte: 0.5 } } |
controversy_score | number | The controversy score of the comment | $gt, $gte, $lt, $lte | { controversy_score: { $lt: 0.8 } } |
created_at | string, must be formatted as an RFC3339 timestamp | The time the comment was created | $eq, $gt, $gte, $lt, $lte | { created_at: { $gte: '2023-12-04T09:30:20.45Z' } } |
Comment sort options
All fields support 1 and -1 directions.
created_atscore: same astopsort optionconfidence_score- same asbestsort optioncontroversy_score- same ascontroversialsort optionupvote_countdownvote_count
Comment Reactions
When adding reactions and the enforce_unique flag is set to true, the existing reaction of a user will be overridden with the new reaction. Use this flag if you want to ensure users have a single reaction per each comment/activity. The default value is false, in which case users can have multiple reactions.
// Add a reaction to a comment
try await feed.addCommentReaction(
commentId: "comment_123",
request: .init(type: "like")
)
// Remove a reaction from a comment
try await feed.deleteCommentReaction(
commentId: "comment_123",
type: "like"
)Overview of the reaction model
Comment Threading
let commentList = client.activityCommentList(
for: .init(
objectId: "activity_123",
objectType: "activity",
depth: 3,
limit: 20
)
)
let comments = try await commentList.get()
// Get replies of a specific parent comment
let replyList = client.commentReplyList(
for: .init(
commentId: "parent_123"
)
)
let replies = try await replyList.get()Reading comment replies supports the same sort parameters as reading comments does.
Restricting comment replies
Set who can add comments
When creating an activity it's possible to set who can add comments. Possible options:
- Everyone (this is the default setting)
- Only people I follow
- Nobody
The activity author is always allowed to add comments regardless of the reply settings.
const response = await feed.addActivity({
type: "post",
text: "apple stock will go up",
restrict_replies: "people_i_follow", // Options: "everyone", "people_i_follow", "nobody"
});Show/hide comment input
If a user isn't allowed to add comments, it's a good idea to hide the comment input.
When everyone/nobody can comment this is straightforward. However if only people the activity author follows can comment, we have to check if there are any feeds owned by the current user that is followed by the activity author, the code snippet below shows how to check this:
const activity: ActivityResponse = /* fetch a single activity or read a feed */;
// Lists follow relationships where
// - target feed is owned by current user
// - source feed is owned by activity author
const feed = client.feed(
activity.current_feed.group_id,
activity.current_feed.id,
);
console.log(feed.currentState.own_followings);own_followings is only set when reading a feed/activity from client-side, for server-side requests it will be empty.
- When fetching a single activity,
own_followingsis set by default - When reading a feed, you have to explicitly enable fetching
own_followings:
feed.getOrCreate({ enrichment_options: { enrich_own_followings: true } });Overview of the comment model
Add comments in batch
let response = try await feed.addCommentsBatch(
request: .init(
comments: [
.init(
id: "comment_123", // id is optional, but must be unique. will be auto-generated if not provided
comment: "So great!",
custom: ["sentiment": "positive"],
objectId: "activity_123",
objectType: "activity"
),
]
)
)