2017-11-14 4 views
0

次の関数ランクは、データベースの親を正しくカウントしますが、Group.query(user_id == 1).rank(0、Group.query。 user_id == 1))非常に効率的ではないようです。この関数を書く良い方法はありますか?sqlalchemyデータベースの親を効率的に数えようとしています

class Group(db.Model): 
    #data 
    id=db.Column(db.Integer, primary_key=True) 
    name=db.Column(db.String(32), nullable=False) 
    #relationships 
    parent_id=db.Column(db.Integer, db.ForeignKey('group.id')) 
    children=db.relationship('Group', backref=db.backref('parent', remote_side=[id])) 

    def rank(self, count, parent): 
     if parent.parent: 
      count=count+1 
      parent.rank(count, parent.parent) 
     else: 
      return count 
+0

つまり、入れ子レベルを数えようとしていますか?どのDBを使用していますか?また、なぜ 'self'を使うのではなく、' parent'引数と同じインスタンスを 'rank()'に渡すのですか? –

+0

私はデータベースにsqliteを使用しています。私は自己を使ってみましたが、それはちょうど0を返し続けました。あなたが5人の親を持っていれば私の考えは5です。データベースは自己参照型なので、新しい見た目がルートとして付けられたときに変更できるようにする必要があります。 –

答えて

2

メソッドを呼び出すインスタンスを別の引数として渡すことは冗長であり、関数にはreturn文もありません。ちょうど行くために同じクエリを2回実行することは言うまでもありません。単にselfself.parentを使用することができます。親がない場合、あなたの再帰関数の基本ケースは次のようになります。

class Group(db.Model): 

    def rank(self): 
     if not self.parent: 
      return 0 

     else: 
      # Python has no TCO, so no point in trying to 
      # use an accumulator 
      return 1 + self.parent.rank() 

しかし、あなたは深くネストされた構造を持っている場合は、これは理想的に行われない場合がありますことを右ですが、簡単な再帰をネストのほんの一部のレベルのためにより複雑な方法に打ち勝つかもしれない。インスタンス上のGroup.parentのすべての最初のアクセスは、新しいSELECT文をDBに発行します。あなたはあなたのデータに操作を取ることができ、言い換えればDBでそれを実行することができます。構造のようなツリーはrecursive Common Table Expressionで扱うことができます。

def rank(self): 
    cls = type(self) 
    parents = db.session.query(cls.parent_id).\ 
     filter_by(id=self.id).\ 
     cte(recursive=True) 

    parent_alias = db.aliased(parents) 
    group_alias = db.aliased(cls) 

    parents = parents.union_all(
     db.session.query(group_alias.parent_id). 
      filter(group_alias.id == parent_alias.c.parent_id)) 

    # Subtract one so that only the parents count 
    return db.session.query(db.func.count() - 1).\ 
     select_from(parents).\ 
     scalar() 

あなたがカウントSQL側にいくつかの時間を必要とする場合にも、おそらく、hybrid propertyにして、これを回すことができます。

+0

これはPythonです。 –

関連する問題