ellipticaldoor
ellipticaldoor

Reputation: 1272

How to search through mongoose ObjectId in feathers?

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?

Profiles

 Mongoose model

{
    name: { type: String, trim: true, required: true },
    labels: [{ type: ObjectId, ref: 'Labels' }],
}

Feathers api get response to profiles

get http://localhost:3030/profiles

{
    "name" : "foo",
    "labels" : [
        "594ceeff6905e622425f523b",
        "594ceeff6905e622425f523c",
        "594ceeff6905e622425f523d"
    ],
}

{
    "name" : "bar",
    "labels" : [
        "594ceeff6905e622425f523e",
        "594ceeff6905e622425f523d"
    ],
}

Labels

 Mongoose model

{
    name: { type: String, trim: true, unique: true, required: true },
}

Feathers api get response to labels

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

Answers (3)

ellipticaldoor
ellipticaldoor

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

Daff
Daff

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

Ninja
Ninja

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

Related Questions