2016-12-09 2 views
2

Прости меня, если я путаю терминологию здесь, но я, выполняющей операцию соединения в агрегации с помощью оператора «$» поиска, как показано здесь:

db.collection('items').aggregate([{$match: {}}, 
{ 
    $lookup: { 
     from: 'usr', 
     localField: 'usr._id', 
     foreignField: '_id', 
     as: '__usr' 
    } 
}, { 
    $project: { 
     info: 1, 
     timestamp: 1, 
     usr: { 
      "$arrayElemAt": [ "$__usr", 0 ] 
     } 
    } 
}], (err, result) => { 
    res.json(result); 
    db.close(); 
}); 

Я выполняю проекцию на результат агрегирования, и я использую '$ arrayElemAt' для извлечения единственного совпадения 'usr' из результирующего массива. По очевидным причинам я не хочу возвращать всю запись «usr», которая содержит конфиденциальную информацию. Что я хочу сделать, это выполнить проекцию на элемент, возвращенный с помощью операции $ arrayElemAt. Единственный способ, которым я был в состоянии сделать это состоит в использовании дополнительной проекции исходной проекции, так как:

db.collection('items').aggregate([{$match: {}}, 
{ 
    $lookup: { 
     from: 'usr', 
     localField: 'usr._id', 
     foreignField: '_id', 
     as: '__usr' 
    } 
}, { 
    $project: { 
     info: 1, 
     timestamp: 1, 
     usr: { 
      "$arrayElemAt": [ "$__usr", 0 ] 
     } 
    } 
}, { 
    $project: { 
     info: 1, 
     timestamp: 1, 
     usr: { 
      "username": 1 
     } 
    } 
}], (err, result) => { 
    res.json(result); 
    db.close(); 
}); 

Есть ли способ сделать это без дублированного проекции?

ответ

3

Вы можете присвоить возвращаемое значение $arrayElemAt переменной с использованием выражения $let и использовать точечную нотацию для доступа к полю поддокумента в выражении in.

"usr": { 
    "$let": { 
     "vars": { 
      "field": { 
       "$arrayElemAt": [ "$__usr", 0 ] 
      } 
     }, 
     "in": "$$field.username" 
    }