pythonmongodbpymongomotordriver

How to find an objects (which contains fields) in Motor MongoDB by entering its incomplete or inaccurate name?


I am creating an economic Discord bot on PyCord with a shop where items can be added. I want it to be possible to purchase an item without entering its exact name, and if multiple items are found, a list of found items should be displayed. The user can then simply choose the item (I can do this myself).

However, I ran into the problem of searching for objects in MongoDB, I tried to use the $regex operator, but it didn't find anything.

I want the search to be done something like this: The user enters a query with the name of the item, most likely not accurate, not complete, etc., but for the bot to try to find this item. For example:

Request: "item"

Database:

 Shop: Object
    Items: Object
        Item A: Object
            price: 280
        Item B: Object
            price: 250
        Item C: Object
            price: 200
            description: "Good Item"

In this case, it should find all the Item objects (A, B, C), and output them as a list and the user will have to choose one (I can figure this out myself) I hope my question was clear :)

My code:

search = await economy_db.find_one({"_id": ctx.guild.id, "Shop.Items": {"$regex": "item"}})

Solution

  • The problem is that you're using find_one which always returns one object.
    You should be using the find method which returns all the documents that satisfy the query.

    Adding the usage of re (python regular expression module) gives:

    import re
    
    matching_items = list(economy_db.find({'Shop.Items': re.compile(<YOUR_REGEX>)}))
    

    Or use the $regex operator in MongoDB:

    matching_items = list(economy_db.find({'Shop.Items': {'$regex': <YOUR_REGEX>}}))
    

    Mind two caveats:

    1. If you want the regex search to be case insensitive then in the first example you should add re.IGNORECASE to the compile function. And $options: 'i' to the $regex operator in the second example.

    2. I did not include the "_id": ctx.guild.id part as it is unique to each document, and we want all the documents which their item name satisfies the regex search.

    Hope it helps!