Conforme sugerido neste post, proponho aqui minha pergunta.
Tenho um MongoDB collections spots que tem documentos que representam a amizade entre dois usuários
{
"_id": "64a337de4538a04610900f0c",
"user1": "6468022102781d442b82afd7",
"user2": "648c7b6b75231cd99e43d7ab",
"areFriends": true
}
Meu objetivo é escrever uma agregação que, dados dois IDs de usuários, retorne o grau de separação deles. Para ser claro, algo assim:
- 1 = amigos diretos
- 2 = amigos de amigos
- 3+ etc..
Me deparei com o exemplo acima de $graphLookup e agora estou pensando em como implementar algo semelhante.
A diferença entre meu caso e o outro post é que meus documentos não têm uma relação unidirecional (de-para), mas bidirecional (usuário1, usuário2); portanto, não há garantia de que o usuário desejado seja armazenado como usuário1 ou usuário2.
Em outras seções do meu código, resolvo esse problema ordenando os IDs de entrada ou usando condições como esta:
$cond: {
if: { $eq: ['$user1', userId] },
then: '$user2',
else: '$user1',
},
No entanto, entendi que as condições não são suportadas conforme arquivadas (como connectFromField ) em $graphLookup
Alguém tem alguma pista sobre como enfrentar esse problema em particular? Ficaria muito agradecido. Obrigado.
EDIT esta é uma versão revisada do pipeline de agregação proposto por Ray
{ $match: { user1: id1 } },
{
$graphLookup: {
from: 'spots',
startWith: '$user1',
connectFromField: 'user2',
connectToField: 'user1',
as: 'friendshipsViewLookup',
depthField: 'degree',
maxDepth: 2,
},
},
{
$unwind: {
path: '$friendshipsViewLookup',
preserveNullAndEmptyArrays: true,
},
},
{ $match: { 'friendshipsViewLookup.user2': id2 } },
{
$project: {
user1: 1,
user2: '$friendshipsViewLookup.user2',
degree: {
$add: ['$friendshipsViewLookup.degree', 1],
},
},
},
{
$group: {
_id: { user1: '$user1', user2: '$user2' },
minDegree: { $min: '$degree' },
},
},
{
$project: {
user1: '$_id.user1',
user2: '$_id.user2',
degree: '$minDegree',
},
}
Você pode criar uma visualização ad-hoc para facilitar sua pesquisa. Ao criar a visualização
friendshipsView
, você pode limitar o escopo da pesquisa (e, assim, melhorar o desempenho da pesquisa) definindo filtros como"areFriends": true
. O ponto mais importante para criar a visualização é que também "classificamos" o campouser1
anduser2
. Usamos$min
and$max
para garantiruser1
que seja sempre o menor queuser2
. Dessa forma, você pode executar o$graphLookup
normalmente.Mongo Playground para demonstrar a criação da vista
Depois que a visualização for criada, você só precisa executar um comando
$graphLookup
como a resposta do SO que você forneceu.Mongo Playground para demonstrar a consulta da visualização
Nota: Como estamos especificando os 2 usuários de entrada para pesquisa ao criar a visualização, se um novo par de usuários for inserido, precisaremos atualizar/recriar a visualização. Você pode considerar uma "classificação" única e definitiva para a coleção usando uma atualização com um pipeline de agregação como este . Dessa forma, você não precisa criar uma nova visualização toda vez.
EDIT: Mesmo que a coleção seja indexada, isso pode não beneficiar esse pipeline de agregação, pois estamos realizando a agregação na visualização, que é computada ad-hoc. Você pode considerar usar a visualização materializada sob demanda , que na verdade armazena nossa visualização computada no banco de dados. A etapa é semelhante a como criamos a visualização. Apenas adicionamos um
$out
/$merge
no final do pipeline de agregação.friendshipsView
coleção existente.$out
Parque infantil Mongo
Agora, sua visualização está pronta para a consulta.
Com sua consulta revisada, você pode ver que ela está sendo usada
IXSCAN
na exibição indexada.explain
saída parcial :Parque infantil Mongo