Reputation: 1272
I have two feathers services, one for profiles and the other one for labels.
A profile can have array of ObjectId labels from other collections.
Now I have an input for search and a user types "linux"
The profile foo should be returned because it contains the id "594ceeff6905e622425f523b" in the labels array.
This kind of search query through ObjectId between objects is possible through feathers?
{
name: { type: String, trim: true, required: true },
labels: [{ type: ObjectId, ref: 'Labels' }],
}
get http://localhost:3030/profiles
{
"name" : "foo",
"labels" : [
"594ceeff6905e622425f523b",
"594ceeff6905e622425f523c",
"594ceeff6905e622425f523d"
],
}
{
"name" : "bar",
"labels" : [
"594ceeff6905e622425f523e",
"594ceeff6905e622425f523d"
],
}
{
name: { type: String, trim: true, unique: true, required: true },
}
get http://localhost:3030/labels
{
"_id": "594ceeff6905e622425f523b",
"name": "linux"
},
{
"_id": "594ceeff6905e622425f523c",
"name": "systemd"
},
{
"_id": "594ceeff6905e622425f523d",
"name": "mongodb"
},
{
"_id": "594ceeff6905e622425f523e",
"name": "javascript"
}
Now I have to populate all the labels on the profiles response, send all the profiles and then filter them on the front with that value of the input for search.
As the database grows this is going to be very inefficient, it has to exist a better way of doing this right?
Upvotes: 1
Views: 1891
Reputation: 1272
I the end I just two calls to the api like this:
computed: {
...mapState('profiles', { profiles: 'keyedById' }),
...mapState('labels', { labels: 'keyedById' }),
},
methods: {
...mapActions('profiles', { findProfiles: 'find' }),
async fetch() {
const labels = this.labels
const search = this.search_input.toLowerCase()
// Generates an array of matched labels per profile
const labels_id = Object.keys(labels).filter(label => {
const name = labels[label].name.toLowerCase()
return name.includes(search)
})
// Searches profiles by name or labels
this.findProfiles({
query: {
$or: [
{
name: { $regex: search, $options: 'igm' },
},
{ labels: { $in: labels_id } },
],
$populate: ['user'],
$sort: { updatedAt: -1 },
},
})
},
},
Upvotes: 0
Reputation: 44215
Feathers does not restrict you on anything that you can do with Mongoose itself and for what you would like to do you can use the Mongoose query population.
The feathers-mongoose
adapter supports this through the $populate query parameter so querying
http://localhost:3030/labels?$populate=labels
Should do what you are looking for.
Upvotes: 2
Reputation: 496
You can try code like this
Profile.find({}).populate({
path: 'labels',
match: {
name: {
$regex: new RegExp(searchText, 'i');
//searchText: passed from the front end.
}
}
}).then(function(profiles){
var filteredProfiles = profiles.forEach(function(profile){
return profile.labels; //will be null for items don't match the
//searching regex.
//resolve the filtered profiles to the front end.
})
},function(error){
//Error handling
})
Upvotes: 2