Search code examples
c#asp.net-mvcentity-framework

Is there a better way to get Non-friends to appear in "People you may know" Section?


I'm trying to make a Social App like Facebook where you can add people as friends.

I want to add a "People you may know section" in which all application users appears except your friends.

I created a model class ApplicationUser that has a self many-to-many relationship so that a user can have multiple friends. Here's the definition of ApplicationUser class:

public class ApplicationUser : IdentityUser
{
    public string Fullname { get; set; }

    public DateOnly BirthDate { get; set; }

    public string? ProfilePicUrl { get; set; }
    public string Bio {  get; set; }

    public ICollection<User_Friend> Users { get; set; }
    public ICollection<User_Friend> Friends { get; set; }
}

And here's the definition of User_Friend model class that maps the M-N relationship:

public class User_Friend
{
    public int Id { get; set; }

    public string UserId { get; set; }
    public ApplicationUser User { get; set; }

    public string FriendId { get; set; }
    public ApplicationUser Friend { get; set; }

    public DateTime FriendsSince { get; set; }
}

Here's my code; it's working as expected but it looks like there must be a better or cleaner way

public IActionResult Index()
{
    var claim = (ClaimsIdentity)User.Identity;
    var user = claim.FindFirst(ClaimTypes.NameIdentifier);

    //everyone ids except me
    List<string> AllIds  = _context.applicationUsers
                                   .Where(u => u.Id != user.Value)
                                   .Select(x => x.Id).ToList();

    // friends ids
    List<string> friendsIds = _context.user_Friends 
                                      .Where(u => u.UserId == user.Value)
                                      .Select(x => x.FriendId)
                                      .ToList();

    // non-friends ids
    List<string> nonFriendsIds = AllIds.Except(friendsIds).ToList();

    List<ApplicationUser> nonFriends = new List<ApplicationUser>();
    
    if (user != null)
    {
        foreach (var x in nonFriendsIds)
        {
            nonFriends.Add(_context.applicationUsers.FirstOrDefault(u => u.Id == x));
        }
    }

    return View(nonFriends);
}

Solution

  • You could get non-friends like:

    var friendIds = _context.ApplicationUsers
        .WHere(x => x.Id == user.Value)
        .SelectMany(x => x.Friends.Select(uf => uf.FriendId))
        .ToList();
    
    var nonFriends = _context.ApplicationUsers
        .Where(x => x.Id != user.Value 
            && !friendIds.Contains(x.Id))
        .ToList();
    

    Note that code like this will absolutely not scale well as the collection of users grows. Imagine Facebook with hundreds of millions of users and many multiples of that in Bot/Fake accounts... :)

    Something like a "people you might know" would be looking at things like "friends of your friends" and other information like if you are tracking details like where you went to school, where you work, etc. and people that went to the same school around the same time, or worked at the same company at the same time, etc.