Что вы можете сделать, это использовать aggregate
с $addFields
и $cond
, чтобы создать поле с именем, по которому вы хотите отсортировать, а затем отсортировать по этому полю. Следующий фрагмент будет получать каждые Foo
и сортировать их по названию компании или по имени + фамилии, если companyAsPrimaryName
равно false.
const data = await Foo.aggregate([
{
// basically .populate('client') in our case
$lookup: {
from: 'clients',
localField: 'client',
foreignField: '_id',
as: 'client'
}
},
{
// deconstruct the client array into one object
$unwind: '$client'
},
{
// add a computed field for sorting
$addFields: {
sortName: {
$cond: {
if: {
$eq: ['$client.companyAsPrimaryName', true]
},
then: '$client.company',
else: {
$concat: ['$client.firstName', '$client.lastName']
}
}
}
}
},
{
$sort: {
sortName: 1
}
}
])
console.log(data)
Здесь Foo
- это модель, содержащая client
как поле. Обратите внимание, что это будет включать это поле в результат. Если вы хотите пропустить некоторые поля, вы можете добавить стадию $project
, чтобы выбрать поля.
Вот фрагмент кода, который я использовал для локального тестирования:
const mongoose = require('mongoose')
const Client = mongoose.model('Client', {
firstName: String,
lastName: String,
company: String,
companyAsPrimaryName: Boolean
})
const Foo = mongoose.model('Foo', {
name: String,
client: { type: mongoose.Types.ObjectId, ref: 'Client' }
})
// Call this in `start()` to populate some sample data
const create = async () => {
const client1 = await new Client({
firstName: 'Alpha',
lastName: 'Alphaname',
company: 'Alphabet',
companyAsPrimaryName: true
}).save()
const client2 = await new Client({
firstName: 'John',
lastName: 'Wayne',
company: 'Google',
companyAsPrimaryName: true
}).save()
const client3 = await new Client({
firstName: 'Bravo',
lastName: 'Bretty',
company: 'Zulu Solutions',
companyAsPrimaryName: false
}).save()
await new Foo({
name: 'Toaster',
client: client1
}).save()
await new Foo({
name: 'Lunchbox',
client: client1
}).save()
await new Foo({
name: 'Treadmill',
client: client1
}).save()
await new Foo({
name: 'Tapas',
client: client2
}).save()
await new Foo({
name: 'Ananas',
client: client2
}).save()
await new Foo({
name: 'Zapiers',
client: client2
}).save()
await new Foo({
name: 'Brets',
client: client3
}).save()
await new Foo({
name: 'Xrats',
client: client3
}).save()
await new Foo({
name: 'Abins',
client: client3
}).save()
}
const start = async () => {
await mongoose.connect('mongodb+srv://CONNECTION STRING HERE', {
useNewUrlParser: true,
useUnifiedTopology: true
})
const data = await Foo.aggregate([
{
// basically .populate('client') in our case
$lookup: {
from: 'clients',
localField: 'client',
foreignField: '_id',
as: 'client'
}
},
{
// deconstruct the client array into one object
$unwind: '$client'
},
{
// add a computed field for sorting
$addFields: {
sortName: {
$cond: {
if: {
$eq: ['$client.companyAsPrimaryName', true]
},
then: '$client.company',
else: {
$concat: ['$client.firstName', '$client.lastName']
}
}
}
}
},
{
$sort: {
sortName: 1
}
}
])
console.log(data)
}
start().then(() => {
console.log('ready')
mongoose.disconnect()
})