読者です 読者をやめる 読者になる 読者になる

MongoDBのORM MongoEngine part.2

今回はクエリ編

基本はobjects

User.objects(name = "太朗")

これでnameフィールドが太朗である全てのドキュメントが返ります
存在しない場合は空の配列が返ります

一件だけ欲しい場合は

User.objects(name = "太朗").first()

存在しなければNoneが返ります

色々

User.objects(name = "太朗" , age = 32) #and
User.objects(name="太朗").limit(10)
User.objects(name="太朗").skip(10)

User.objects(name="太朗").order_by("id")  #id順に
User.objects(name="太朗").order_by("-id") #逆順はマイナスを付ける
User.objects(name="太朗").order_by("id" , "datetime") #複数

User.objects(name="太朗").count() #件数
len(User.objects(name="太朗")) #これは0.8以降では遅いのでやっちゃダメです count()使いましょう

アンダースコアを二つ重ねて色んなクエリ

User.objects(name__ne="次郎") #nameフィールドが次郎では無いもの
User.objects(age__lt=30) #ageが30未満
User.objects(name__icontains = "朗") #nameフィールドに朗が含まれているもの

User.objects(age__exists = True) #ageフィールドが存在するもの(フィールドの値は考慮されない)
User.objects(age__exists = False) #ageフィールドが存在しないもの

詳細は以下
http://docs.mongoengine.org/en/latest/guide/querying.html#query-operators
ne – not equal to
lt – less than
lte – less than or equal to
gt – greater than
gte – greater than or equal to
not – negate a standard check, may be used before other operators (e.g. Q(age__not__mod=5))
in – value is in list (a list of values should be provided)
nin – value is not in list (a list of values should be provided)
mod – value % x == y, where x and y are two provided values
all – every item in list of values provided is in array
size – the size of the array is
exists – value for field exists
The following operators are available as shortcuts to querying with regular expressions:

exact – string field exactly matches value
iexact – string field exactly matches value (case insensitive)
contains – string field contains value
icontains – string field contains value (case insensitive)
startswith – string field starts with value
istartswith – string field starts with value (case insensitive)
endswith – string field ends with value
iendswith – string field ends with value (case insensitive)
match – performs an $elemMatch so you can match an entire document within an array
There are a few special operators for performing geographical queries, that may used with GeoPointFields:

scalar(field)

条件にマッチするドキュメントのidだけ欲しい場合

ids = []
for user in User.objects(name="太朗") :
    ids.append(user.id)
#あるいは
ids =[user.id for user in User.objects(name="太朗") ]

これは面倒ですし時間がかかるのでscalar()を使いましょう

User.objects(name="太朗").scalar("id") #これでidのみが含まれた配列が返る

注意点としては返るオブジェクトは配列っぽく見えますしほとんどpythonのlistと同じなのですが、厳密にはmongoengineのQuerySetというオブジェクトです。
もしpythonのlistしか受け付けないライブラリなんかに投げる場合はエラーが出る可能性があるので、

list( User.objects(name="太朗").scalar("id") )

とするのが無難です。

onlyとexclude

u = User.objects(name="太朗").only("name").first() #nameフィールドのみDBから取ってきます
u.name #=> 太朗
u.age #=> None 

使わないフィールドのデータは取らないようにすることでMongoDBにかかる負荷を減らす事ができます
excludeはonlyとは逆の働きをします

User.objects(name="太朗").exclude("image_file") #image_file以外のフィールドを取ってきます

クエリフィルター

一度発行したクエリをさらに絞ることができます

users = User.objects(name = "太朗")
users = users.filter( age = 32 ) #ageで絞る

この場合はLazyLoadingになります。

0.7系と0.8系でのfilterの挙動の違い
users = User.objects(name = "太朗")
#0.7では
users.filter( age = 32 ) #この時点で元のusersが破壊的な変更
#0.8では
users.filter( age = 32 ) #元のusersは変更されない
users = users.filter( age = 32 )  #変更したいならこうする


他にも便利な機能がたくさんあります
http://docs.mongoengine.org/en/latest/guide/querying.html
http://docs.mongoengine.org/en/latest/apireference.html#module-mongoengine.queryset