나는 mongodb의 List 타입을 $in 으로 검색하려고 하는데..이게 지원안된다.


태그 같은건 ["한국", "여행"] 이런식으로 list 타입으로 관리되고, 해쉬태그처럼 사용하는거라 $in 검색을 하고 싶은데 

(=성능상 contains 하면 데이터 많으면 힘들다)


관계형 데이터베이스에서는 이런 N개의 데이터는 없었기 때문일까? 기본적으로는 지원안된다.


column_searchable_list = ('tags', )  # Document 를 ListField(StringField()) 필드로 구성했다고 했을때...


이걸 하려면 ModelView를 고쳐서 쓰면 된다.

참고로 기존 코드만 배끼고 저 파란부분만 추가해서 오버라이딩 한거다.

이 모델뷰를 이용해 구성하면 list<stringField> 구성에 대해서는 $in 검색을 한다.


# -*- coding: utf-8 -*-
import sys

import mongoengine
from flask_admin.contrib.mongoengine.tools import parse_like_term


reload(sys)
sys.setdefaultencoding('utf-8')
from flask_admin.contrib.mongoengine import ModelView
from flask_admin._compat import string_types
from mongoengine import ListField

class CustomModelView(ModelView):
    """
        list 타입 검사 안되는 문제를 해결
    """
    def init_search(self):
        if self.column_searchable_list:
            for p in self.column_searchable_list:
                if isinstance(p, string_types):
                    p = self.model._fields.get(p)  # convert type

                if p is None:
                    raise Exception('Invalid search field')

                # list type (my code)
                if isinstance(p, ListField):
                    p_sub = p.field
                    if type(p_sub) in self.allowed_search_types:
                        self._search_fields.append(p)
                        continue

                field_type = type(p)
                if (field_type not in self.allowed_search_types):
                        raise Exception('Can only search on text columns. ' +
                                        'Failed to setup search for "%s"' % p)
                self._search_fields.append(p)
        return bool(self._search_fields)


    def _search(self, query, search_term):
        op, term = parse_like_term(search_term)
        criteria = None

        for field in self._search_fields:
            if isinstance(field, ListField):
                flt = {'%s__%s' % (field.name, 'in'): (term,)}
            else:
                flt = {'%s__%s' % (field.name, op): term}


            q = mongoengine.Q(**flt)

            if criteria is None:
                criteria = q
            else:
                criteria |= q
 

            return query.filter(criteria)


+ Recent posts