[READ ONLY MIRROR] Spark Social AppView Server github.com/sprksocial/server
atproto deno hono lexicon
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

perf(dataplane): improve knownFollowers and knownInteractions efficiency

+42 -22
+9 -4
data-plane/db/models.ts
··· 165 165 viaCid: { type: String, required: false }, 166 166 }) 167 167 .index({ authorDid: 1, subject: 1 }, { unique: true }) 168 - .index({ subject: 1, createdAt: -1 }); 168 + .index({ subject: 1, createdAt: -1 }) 169 + .index({ subject: 1, authorDid: 1 }); 169 170 170 171 // follows 171 172 ··· 177 178 subject: { type: String, required: true, index: true }, 178 179 }) 179 180 .index({ authorDid: 1, subject: 1 }, { unique: true }) 180 - .index({ subject: 1, createdAt: -1 }); 181 + .index({ subject: 1, createdAt: -1 }) 182 + .index({ subject: 1, authorDid: 1 }); 181 183 182 184 // blocks 183 185 ··· 260 262 viaCid: { type: String, required: false }, 261 263 }) 262 264 .index({ subject: 1, createdAt: -1 }) 263 - .index({ authorDid: 1, createdAt: -1 }); 265 + .index({ authorDid: 1, createdAt: -1 }) 266 + .index({ subject: 1, authorDid: 1 }); 264 267 265 268 // posts 266 269 ··· 340 343 likeCount: { type: Number, required: true, default: 0 }, 341 344 replyCount: { type: Number, required: true, default: 0 }, 342 345 }) 343 - .index({ reply: 1, createdAt: -1 }); 346 + .index({ reply: 1, createdAt: -1 }) 347 + .index({ "reply.parent.uri": 1, authorDid: 1 }) 348 + .index({ "reply.root.uri": 1, createdAt: -1 }); 344 349 345 350 // stories 346 351
+23 -14
data-plane/routes/follows.ts
··· 105 105 106 106 async getFollowsFollowing(viewerDid: string, subjectDids: string[]) { 107 107 /* 108 - * 1. Get all the people Alice is following 109 - * 2. Get all the people Dan is followed by 110 - * 3. Find the intersection 108 + * Find people the viewer follows who also follow each subject. 109 + * Uses aggregation to avoid fetching all followers of popular accounts. 111 110 */ 112 111 113 112 const results: FollowsFollowing[] = []; 114 113 115 - for (const subjectDid of subjectDids) { 116 - // Get people who follow the subject (Dan's followers) 117 - const subjectFollowers = await this.db.models.Follow.find({ 118 - subject: subjectDid, 119 - }); 114 + // Get all people the viewer follows (bounded by viewer's follow count) 115 + const viewerFollows = await this.db.models.Follow.find({ 116 + authorDid: viewerDid, 117 + }).select("subject"); 118 + 119 + const viewerFollowsDids = viewerFollows.map((f) => f.subject); 120 120 121 - const followerDids = subjectFollowers.map((f) => f.authorDid); 121 + if (viewerFollowsDids.length === 0) { 122 + // Viewer follows no one, so no known followers possible 123 + return { 124 + results: subjectDids.map((targetDid) => 125 + new FollowsFollowing({ targetDid, dids: [] }) 126 + ), 127 + }; 128 + } 122 129 123 - // Find which of these followers Alice also follows 130 + for (const subjectDid of subjectDids) { 131 + // Find which of the viewer's follows also follow the subject 132 + // This query is bounded by the viewer's follow count, not the subject's follower count 124 133 const mutualConnections = await this.db.models.Follow.find({ 125 - authorDid: viewerDid, 126 - subject: { $in: followerDids }, 127 - }); 134 + authorDid: { $in: viewerFollowsDids }, 135 + subject: subjectDid, 136 + }).select("authorDid"); 128 137 129 138 results.push( 130 139 new FollowsFollowing({ 131 140 targetDid: subjectDid, 132 - dids: mutualConnections.map((connection) => connection.subject), 141 + dids: mutualConnections.map((connection) => connection.authorDid), 133 142 }), 134 143 ); 135 144 }
+10 -4
data-plane/routes/interactions.ts
··· 161 161 // Get all DIDs the viewer follows 162 162 const viewerFollows = await this.db.models.Follow.find({ 163 163 authorDid: viewerDid, 164 - }); 164 + }).select("subject"); 165 165 const followedDids = viewerFollows.map((f) => f.subject); 166 166 167 167 if (followedDids.length === 0) { ··· 173 173 this.db.models.Like.find({ 174 174 subject: { $in: subjectUris }, 175 175 authorDid: { $in: followedDids }, 176 - }).sort({ indexedAt: -1 }), 176 + }) 177 + .select("uri cid subject authorDid indexedAt") 178 + .sort({ indexedAt: -1 }), 177 179 this.db.models.Repost.find({ 178 180 subject: { $in: subjectUris }, 179 181 authorDid: { $in: followedDids }, 180 - }).sort({ indexedAt: -1 }), 182 + }) 183 + .select("uri cid subject authorDid indexedAt") 184 + .sort({ indexedAt: -1 }), 181 185 this.db.models.Reply.find({ 182 186 "reply.parent.uri": { $in: subjectUris }, 183 187 authorDid: { $in: followedDids }, 184 - }).sort({ indexedAt: -1 }), 188 + }) 189 + .select("uri cid reply.parent.uri authorDid indexedAt text") 190 + .sort({ indexedAt: -1 }), 185 191 ]); 186 192 187 193 // Build result map keyed by subject URI