schapman1974 / tinymongo

A simple wrapper to make a flat file drop in raplacement for mongodb out of TinyDB
MIT License
201 stars 32 forks source link

`$in` operator to search tagged documents #42

Open rochacbruno opened 7 years ago

rochacbruno commented 7 years ago

I have a document like this

{
 '_id': '3c7df42e91c611e7bf575ce0c5482b4b',
 'authors': ['Bruno Rocha'],
 'authors_slug': ['bruno-rocha'],
 'category': 'python/flask',
 'date': datetime.datetime(2017, 9, 4, 20, 10, 26),
 'published': True,
 'slug': 'simple-login-extension-for-flask',
 'tags': ['python', 'flask', 'pythonplanet', 'pyplanet', 'new'],
 'title': 'Simple Login Extension for Flask',
}

It has a 'tags': ['python', 'flask', 'pythonplanet', 'pyplanet', 'new'] and I have more documents with tag python

When I search using {'tags': 'python'}

col.find({'tags': 'python'}).count()
25.09 22:19:22 tinymongo.tinymongo DEBUG    query to parse2: {'tags': 'python'}
25.09 22:19:22 tinymongo.tinymongo DEBUG    query: {'tags': 'python'} prev_query: None
25.09 22:19:22 tinymongo.tinymongo DEBUG    conditions: tags python
25.09 22:19:22 tinymongo.tinymongo DEBUG    c: QueryImpl('==', ('tags',), 'python')
25.09 22:19:22 tinymongo.tinymongo DEBUG    new query item2: QueryImpl('==', ('tags',), 'python')
0

Ok that is expected so lets use {'$in': 'python'}

col.find({'tags': {'$in': 'python'}}).count()
25.09 22:20:34 tinymongo.tinymongo DEBUG    query to parse2: {'tags': {'$in': 'python'}}
25.09 22:20:34 tinymongo.tinymongo DEBUG    query: {'tags': {'$in': 'python'}} prev_query: None
25.09 22:20:34 tinymongo.tinymongo DEBUG    conditions: tags {'$in': 'python'}
25.09 22:20:34 tinymongo.tinymongo DEBUG    c: None
25.09 22:20:34 tinymongo.tinymongo DEBUG    query: {'$in': 'python'} prev_query: tags
25.09 22:20:34 tinymongo.tinymongo DEBUG    conditions: $in python
25.09 22:20:34 tinymongo.tinymongo DEBUG    c: None
25.09 22:20:34 tinymongo.tinymongo DEBUG    new query item2: None
0

or with a list: {'$in': ['python', 'flask']}

col.find({'tags': {'$in': ['python', 'flask']}}).count()
25.09 22:21:09 tinymongo.tinymongo DEBUG    query to parse2: {'tags': {'$in': ['python', 'flask']}}
25.09 22:21:09 tinymongo.tinymongo DEBUG    query: {'tags': {'$in': ['python', 'flask']}} prev_query: None
25.09 22:21:09 tinymongo.tinymongo DEBUG    conditions: tags {'$in': ['python', 'flask']}
25.09 22:21:09 tinymongo.tinymongo DEBUG    c: None
25.09 22:21:09 tinymongo.tinymongo DEBUG    query: {'$in': ['python', 'flask']} prev_query: tags
25.09 22:21:09 tinymongo.tinymongo DEBUG    conditions: $in ['python', 'flask']
25.09 22:21:09 tinymongo.tinymongo DEBUG    c: None
25.09 22:21:09 tinymongo.tinymongo DEBUG    query: {'tags': 'python'} prev_query: None
25.09 22:21:09 tinymongo.tinymongo DEBUG    conditions: tags python
25.09 22:21:09 tinymongo.tinymongo DEBUG    c: QueryImpl('==', ('tags',), 'python')
25.09 22:21:09 tinymongo.tinymongo DEBUG    query: {'tags': 'flask'} prev_query: None
25.09 22:21:09 tinymongo.tinymongo DEBUG    conditions: tags flask
25.09 22:21:09 tinymongo.tinymongo DEBUG    c: QueryImpl('==', ('tags',), 'flask')
25.09 22:21:09 tinymongo.tinymongo DEBUG    new query item2: QueryImpl('or', frozenset({('==', ('tags',), 'python'), ('==', ('tags',), 'flask')}))
0

I checked the source code and currently the $in operator only works in the reverse way, it works currently to match a single field against an array of possibilities. But not to check an array against a single value or array.

rochacbruno commented 7 years ago

Test case for future implementation

db.tags.insert({"tags":["red", "tall", "cheap"]});
db.tags.insert({"tags":["blue", "tall", "expensive"]});
db.tags.insert({"tags":["blue", "little", "cheap"]}); 

# find all blue
db.tags.find({tags: "blue"})

# find all blue and cheap
db.tags.find({ tags: { $all: ["cheap", "blue"] } } )

# find all not blue
db.tags.find({tags: { $ne: "blue" } })

# find all "blue" and "cheap" but not "red" and not "tall"
db.tags.find({ $and: [ {tags: { $all: ["blue", "cheap"] } }, { tags: { $nin: ["red", "tall"] } } ] })
rochacbruno commented 7 years ago

I did a workaround saving a string version of my tags as {'tags_string': ',python,flask,other,another,'}

and querying with

col.find({'tags_string': {'$regex': '.*,python,.*'}})
rochacbruno commented 7 years ago

@schapman1974 @jjonesAtMoog can you guys add hacktoberfest label to this issue please?