Okay, I have ORMed my sql statement:

pn = db.session.query(PNModel.post_id,
db.func.array_agg(PNModel.node_id.distinct()).label('pn_nodes')).group_by(PNModel.post_id)
n =
db.session.query(db.func.array_agg(NodesModel.id.distinct()).label('n_nodes')).filter(NodesModel.project_uuid
==
    project_uuid).filter(NodesModel.topic.in_(topic_list)).subquery()
query = db.session.query(pn.c.post_id).filter(pn.c.pn_nodes ==
db.session.query(n.c.n_nodes))
results = query.all()

This returns what my original SQL returned. My next step is to get all the
posts of the post_id in the list

post_id_list = [result[0] for result in results]
posts = PostsModel.find_by_id_list(id_list=post_id_list)

I'm just wondering, if there is an easy way to get the post object from the
query instead of doing the above.

Desmond


On Tue, 11 Jun 2019 at 08:30, Desmond Lim <limwen...@gmail.com> wrote:

> Hi Simon,
>
> Sorry I think I really didn't make what I'm asking for clear.
>
> I have these codes
>
> nodes =
> NodesModel.find_by_project_uuid_and_topic_list(project_uuid=project_uuid,
> topic_list=node_dict['topics'])
> node_id_list = [node.id for node in nodes]
>
> select_sql = text('WITH pn_o AS (SELECT post_id, ARRAY_AGG(DISTINCT
> node_id) AS pn_nodes FROM pn GROUP BY post_id), '
>                   'n_o AS (SELECT ARRAY_AGG(DISTINCT node_id) as n_nodes
> FROM pn WHERE node_id IN :input_tuple) '
>                   'SELECT post_id FROM pn_o WHERE pn_nodes = (SELECT
> n_nodes FROM n_o)')
>
> params = {"input_tuple": tuple(node_id_list)}
> results = db.session.execute(select_sql, params).fetchall()
>
> Which does what I want. In the end, in results, I get a list of posts that
> have nodes that contain all the topics I need, in other words, the posts
> contain all the topic words.
>
> I'm just wondering, if there is a way to ORM the select_sql as I would
> prefer to work with the models than the raw SQL. And I'm doing it this way
> because I want the server to do the heavy lifting.
>
> Desmond
>
> On 10 Jun 2019, 22:41 +0800, Simon King <si...@simonking.org.uk>, wrote:
>
> I'm still not sure I understand. Here's an example that does what I
> *think* you're asking for:
>
> import sqlalchemy as sa
> import sqlalchemy.orm as saorm
> from sqlalchemy.ext.declarative import declarative_base
>
> Base = declarative_base()
>
>
> pn = sa.Table(
> "pn", Base.metadata,
> sa.Column("post_id", sa.Integer, sa.ForeignKey("posts.id")),
> sa.Column("node_id", sa.Integer, sa.ForeignKey("nodes.id")),
> )
>
>
> class Node(Base):
> __tablename__ = "nodes"
> id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
> project_uuid = sa.Column(sa.Text, nullable=False)
> topic = sa.Column(sa.Text(20), nullable=False)
>
> posts = saorm.relationship("Post", secondary=pn, backref="nodes")
>
>
> class Post(Base):
> __tablename__ = "posts"
> id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)
> project_uuid = sa.Column(sa.Text, nullable=False)
>
>
> if __name__ == "__main__":
> engine = sa.create_engine("sqlite://")
> Base.metadata.create_all(bind=engine)
> Session = saorm.sessionmaker(bind=engine)
>
> projectid = "42a8e275-f153-452b-99d3-645bdd513ca9"
> topics = ['a', 'b', 'c', 'd']
> nodes = [Node(project_uuid=projectid, topic=t) for t in topics]
> posts = [Post(project_uuid=projectid) for i in range(11)]
>
> import random
> random.seed(0)
> for node in nodes:
> node.posts = random.sample(posts, 4)
>
> session = Session()
> session.add_all(nodes + posts)
> session.flush()
>
> node_ids = [1, 2]
> print("Looking for posts with node IDs: %s" % node_ids)
> posts = (
> session.query(Post)
> .join("nodes")
> .filter(Node.id.in_(node_ids))
> .all()
> )
> for p in posts:
> print("Post %s: Node IDs %s" % (p.id, [n.id for n in p.nodes]))
>
> Simon
>
> On Mon, Jun 10, 2019 at 1:22 PM Desmond Lim <limwen...@gmail.com> wrote:
>
>
> Hi Simon,
>
> The tables and sample data are below.
>
> So first I search the nodes table for a and b, getting the node_id of them
> (in this example, 1 and 2).
>
> Then using the SQL statement, I would get all posts that have 1 and 2 as
> the node_id. So in the example data, 100, 103, 108 will be returned as
> these posts contain the nodes 1 and 2.
>
> Hope this helps.
>
> Desmond
>
> -------------
>
> CREATE SEQUENCE IF NOT EXISTS nodes_id_seq;
>
> CREATE TABLE "public"."nodes" (
> "id" int8 NOT NULL DEFAULT nextval('nodes_id_seq'::regclass),
> "project_uuid" uuid NOT NULL,
> "topic" varchar(20) NOT NULL,
> PRIMARY KEY ("id")
> );
>
> CREATE SEQUENCE IF NOT EXISTS posts_id_seq;
>
>
> CREATE TABLE "public"."posts" (
> "id" int8 NOT NULL DEFAULT nextval('posts_id_seq'::regclass),
> "project_uuid" uuid NOT NULL,
> PRIMARY KEY ("id")
> );
>
> CREATE TABLE "public"."pn" (
> "post_id" int8 NOT NULL,
> "node_id" int8 NOT NULL,
> PRIMARY KEY ("post_id","node_id")
> );
>
> INSERT INTO "public"."nodes" ("id", "project_uuid", "topic", "size",
> "given_id") VALUES
> ('1', '42a8e275-f153-452b-99d3-645bdd513ca9', 'a'),
> ('2', '42a8e275-f153-452b-99d3-645bdd513ca9', 'b'),
> ('3', '42a8e275-f153-452b-99d3-645bdd513ca9', 'c'),
> ('4', '42a8e275-f153-452b-99d3-645bdd513ca9', 'd')
>
> INSERT INTO "public"."posts" ("id", "project_uuid") VALUES
> ('100', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('101', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('102', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('103', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('104', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('105', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('106', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('107', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('108', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('109', '42a8e275-f153-452b-99d3-645bdd513ca9'),
> ('110', '42a8e275-f153-452b-99d3-645bdd513ca9')
>
> INSERT INTO "public"."pn" ("post_id", "node_id") VALUES
> ('1', '100'),
> ('2', '100'),
> ('3', '100'),
> ('2', '101'),
> ('3', '101'),
> ('4', '101'),
> ('5', '101'),
> ('3', '102'),
> ('4', '102'),
> ('1', '103'),
> ('2', '103'),
> ('3', '103'),
> ('2', '104'),
> ('4', '104'),
> ('1', '105'),
> ('4', '105'),
> ('3', '105'),
> ('3', '106'),
> ('4', '106'),
> ('4', '107'),
> ('1', '108'),
> ('2', '108'),
> ('3', '109'),
> ('1', '109'),
> ('4', '109'),
> ('2', '110'),
> ('3', '110')
>
> ALTER TABLE "public"."posts" ADD FOREIGN KEY ("project_uuid") REFERENCES
> "public"."projects"("uuid");
> ALTER TABLE "public"."pn" ADD FOREIGN KEY ("post_id") REFERENCES
> "public"."posts"("id");
> ALTER TABLE "public"."pn" ADD FOREIGN KEY ("node_id") REFERENCES
> "public"."nodes"("id");
>
> On Mon, 10 Jun 2019 at 17:08, Simon King <si...@simonking.org.uk> wrote:
>
>
> Hi Desmond.
>
> I don't really understand your table structure. Could you present it
> in the form of a standalone script that we can run (including sample
> data)?
>
> Thanks,
>
> Simon
>
> On Mon, Jun 10, 2019 at 2:57 AM Desmond Lim <limwen...@gmail.com> wrote:
>
>
> Hi there,
>
> I really have no idea how to do this via sqlalchemy. I have 2 tables:
>
> class NodesModel(db.Model):
> __tablename__ = 'nodes'
>
> id = db.Column(db.BigInteger, primary_key=True)
> topic = db.Column(db.String(20), nullable=False)
>
> pn = relationship("PNModel", backref="nodes")
>
> class PNModel(db.Model):
> __tablename__ = 'pn'
>
> post_id = db.Column(db.BigInteger, db.ForeignKey('posts.id'),
> primary_key=True)
> node_id = db.Column(db.BigInteger, db.ForeignKey('nodes.id'),
> primary_key=True)
>
>
> I will get a list of nodes that have the topic (e.g. one, two). Then
> taking the nodes, I'll select the PN that have both nodes (it can be 1 or
> more) associated with it.
>
> e.g.
>
>
>
> I'm doing it this way at this point:
>
> nodes = NodesModel.find_by_topic_list(topic_list)
> node_id_list = [node.id for node in nodes]
>
> Then running this sql statement:
> WITH pn_1 AS (SELECT post_id, ARRAY_AGG(DISTINCT node_id) AS nodes
> FROM pn GROUP BY post_id),
> nodes_1 AS (SELECT ARRAY_AGG(DISTINCT id) AS s_nodes
> FROM pn WHERE node_id IN (dict(node_id_list))
> SELECT DISTINCT post_id FROM pn_1
> WHERE nodes_1 = (SELECT s_nodes FROM select_nodes);
>
> There has to be a better and more elegant way to do this with SQLAlchemy
> and I can't seem to figure it out. I've tried using subqueries and then I
> realised that I'm actually calling the nodes table twice, which I shouldn't
> have to.
>
> Can anyone tell me how to use the nodes table to get the post_id form pn
> (after which getting the post should be easy via ORM should be easy, I
> think).
>
> Thanks.
> Desmond
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sqlalchemy/CAM%2BCzahgN2TF88p4__5W76DiYO3THD1tV2BgekvX913Mv6nU7Q%40mail.gmail.com
> .
> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sqlalchemy/CAFHwexcmpOTTms0-A9QbiT_DTQey8e-Wzze4W5HoDXZdZ7eJWA%40mail.gmail.com
> .
> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sqlalchemy/CAM%2BCzahCwZ7_yKbFTPvYX4kXTz1bZ%3DoTXGVw1g0eO26qeGBGpg%40mail.gmail.com
> .
> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> SQLAlchemy -
> The Python SQL Toolkit and Object Relational Mapper
>
> http://www.sqlalchemy.org/
>
> To post example code, please provide an MCVE: Minimal, Complete, and
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full
> description.
> ---
> You received this message because you are subscribed to the Google Groups
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to sqlalchemy+unsubscr...@googlegroups.com.
> To post to this group, send email to sqlalchemy@googlegroups.com.
> Visit this group at https://groups.google.com/group/sqlalchemy.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/sqlalchemy/CAFHwexeWqM1m4aXWpuJnzfrUvgzBpq1JOVd_PJ1w-08TDTwzig%40mail.gmail.com
> .
> For more options, visit https://groups.google.com/d/optout.
>
>

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/CAM%2BCzagfcZmCPDHPYUWXTVV%3DzBqq96KSu30JJnO0GbAGt8wn9g%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to