msiemens / tinydb

TinyDB is a lightweight document oriented database optimized for your happiness :)
https://tinydb.readthedocs.org
MIT License
6.84k stars 550 forks source link

Search documents that do not have a specific key #547

Closed aseba closed 1 month ago

aseba commented 1 year ago

I'm looking into a way to search for all documents that do not have a specific key set. Is there a way to do a search like Query().f1.exists() == False or not Query().f1.exists()? How can I find all documents that do not have a specific key?

A solution I found is to write my own not_exist function, but by looking at the code, all query functions call self._generate_test which I can't call in this case because _generate_test literally returns False if there is a KeyError exception, which renders it useless to check for the exact opposite πŸ˜†

def not_exists(self) -> QueryInstance:
        """
        Test for a dict where a provided key not exists.

        >>> Query().f1.not_exists()
        """

        def test(value):
            for part in self._path:
                if part in value.keys():
                        return False
            return True

        return QueryInstance(
            lambda value: test(value),
            (('not_exists', self._path) if self.is_cacheable() else None)
        )
msiemens commented 1 month ago

I think you could combine .exists() with the NOT operator:

from tinydb import TinyDB, Query
db = TinyDB('test.json')
db.truncate()

db.insert({'foo': [{'name': 'bar'}]})
db.insert({'bar': [{'name': 'foo'}]})

query = Query()

# Where `foo` does NOT exist
result = db.search(~query.foo.exists())

# Print the result
print(result)

If this doesn't work, please leave a comment!