简体   繁体   中英

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?

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
})

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.

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 },
            },
        })
    },
},

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM