Возможно, вы могли бы изменить свою структуру, чтобы иметь коллекцию Connections, в которой хранится пара пользовательских идентификаторов. Я не могу сказать, что это было бы более оптимальным, но это оставило бы вам больше возможностей для расширения, например, это поддержало бы наличие типов соединений, некоторые соединения могли бы быть друзьями, другие могли быть из цепочек сообщений между людьми, которые не являются друзьями, не уверен как бы вы это ни называли, но в качестве примера рассмотрите что-то вроде запросов сообщений в мессенджере Facebook.
Еще одним преимуществом этого является то, что он останавливает создание случайного мегадо c, поскольку чей-то список друзей становится все больше и больше. Это также означает, что когда вы выбираете друга-друга, выполняете c, вы также не будете извлекать друзей-друзей, возможно, именно здесь вы ищете оптимизацию.
Соединения могут выглядеть примерно так :
{
instigator: ObjectId("5e91bcd6cd1630213d95f810"),
subordinate: ObjectId("5e57d64d92cc878760086980"),
type: 'friendship'
}
{
instigator: ObjectId("5e91bcd6cd1630213d95f810"),
subordinate: ObjectId("5e57d64d92cc878760086981"),
type: 'friendship'
}
, чтобы представить две дружбы в вашем примере.
Чтобы получить друзей одного пользователя, вы бы запросили что-то вроде Connections.find({ users: ObjectId('5e91bcd6cd1630213d95f810'), type: 'friendship' })
Вы можете использовать агрегат или мон goose заполнить, чтобы обменять userIds для своих документов, прежде чем возвращать их в клиент.