묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
안녕하세요 강사님 질문 있습니다.
안녕하세요 김영한 강사님! 올려주신 강좌 아주 잘 보고 있습니다. 실무에서 사용할법한 부분들도 너무 좋구요 그래서 질문이 있습니다. 질문이 기술적인거라기보다는 성능에 관한 것인데요 만약에 게시판을 테이블을 만들고 각 회원들이 게시판에 글을 씁니다. 그리고 각 글에는 댓글도 달수 있고요 그런데 예를 들면 블라인드의 각 회사별 게시판처럼 게시판이 종류별로 있다고 할때 아래와 같은 경우 어떻게 매핑을 해야할지 감이 잘 오지 않습니다. 게시판수 : 10개 (a,b,c.... 종류별 ) a 게시판에 달린 글수 : 1천만개 a 게시판의 1천만개에 달린 댓글수 : 3천만개 이럴 경우 @OneToMany private List<Comment> comments; @OneToMany private List<Post> posts; (일단 대충 적었습니다.) 라고 했을 경우 서비스쪽에서는 1. 게시판글수 표시 ( 10,566,999개) 2. 댓글수 (30,444,999개) 라고 표기해주고 관리자에서는 --------------------------- 게시판 | 게시글수 | 댓글수 | ---------------------------- a게시판 | 10,566,999개 | 30,444,999개| 라고 보여줘야 할 경우 게시판 테이블에 글수 카운팅 컬럼과 댓글수 카운팅 걸럼을 두는게 좋을지 아니면 community.getComment().size() 뭐 이런식으로 하는게 좋을지 감이 오지를 않습니다. lzay 로딩을 걸어도 결국 getPosts()size(), getComments.size() 할때 저 천만개와 3천만개 데이터를 다 select 할것 같은데요 그래도 성능상 문제가 없을지 고민이 됩니다. 즉, list 객체를 두고 사이즈를 가져와도 무방할런지 아니면 이렇게 데이터가 많을 경우는 차라리 카운트 컬럼을 주는게 나을런지 고민이 됩니다. 아무래도 주문이 엄청난 회사에 계시니 관리자에서 저런식으로 보여주는 곳이 있으실것 같은데 어떻게 하는지 궁금합니다. 긴글 읽어주셔서 감사합니다.
-
미해결남박사의 파이썬으로 실전 웹사이트 만들기
게시판 검색기능 구현 후 데이터를 검색하여도 데이터 없음으로 나옵니다.
안녕하세요 강의를 보며 게시판 검색기능을 구현중인데요, 어떤 부분이 잘못되었는지 게시판 검색을 하여도 데이터 없음으로 나옵니다. 혹시 첨부한 코드에서 무엇이 잘못되었는지 봐주실 수 있을까요? <추가> 정정하면 기존 코드로는 제대로 검색이 이루어지지 않으며 아래와 같이 {}를 query로 바꾸면 아예 데이터 없음으로 나옵니다 datas =board.find(query).skip((page - 1) * limit).limit(limit) #게시물의 총 갯수 tot_count = board.find(query).count() from flask import Flask from flask import request from flask import render_template from flask_pymongo import PyMongo from datetime import datetime from bson.objectid import ObjectId from flask import abort from flask import redirect from flask import url_for import time import math app = Flask(__name__) app.config["MONGO_URI"] = "mongodb://localhost:27017/myweb" mongo = PyMongo(app) @app.template_filter("formatdatetime") def format_datetime(value): if value is None: return "" now_timestamp = time.time() offset = datetime.fromtimestamp(now_timestamp)-datetime.utcfromtimestamp(now_timestamp) value = datetime.fromtimestamp((int(value)/1000)) + offset return value.strftime('%Y-%m-%d %H:%M:%S') @app.route("/list") def lists(): #페이지값(값이 없는 경우 기본값은 1) page = request.args.get("page", 1, type=int) #한페이지당 몇개의 게시물을 출력할지 limit = request.args.get("limit", 5, type=int) search = request.args.get("search", -1, type=int) keyword = request.args.get("keyword", type=str) #최종적으로 완성된 쿼리를 만들 변수 query = {} #검색어 상태를 추가할 리스트변수 search_list = [] if search == 0: search_list.append({"title": {"®ex": keyword}}) elif search == 1: search_list.append({"contents": {"®ex": keyword}}) elif search == 2: search_list.append({"title": {"®ex": keyword}}) search_list.append({"contents": {"®ex": keyword}}) elif search == 3: search_list.append({"name": {"®ex": keyword}}) if len(search_list) > 0: query = {"$or": search_list} print(query) board = mongo.db.board #skip (2번쩨 페이지-1)*10 -> 앞페이지 10개 skip, 이후부터 10개까지 출력 datas =board.find({}).skip((page - 1) * limit).limit(limit) #게시물의 총 갯수 tot_count = board.find({}).count() # 마지막 페이지의 수 last_page_num = math.ceil(tot_count/limit) #페이지 블록 5개씩 표기 block_size = 5 #현재 블록 위치 block_num = int((page - 1)/ block_size) #블럭의 시작 위치 block_start = int((block_size * block_num) +1) #블럭의 끝 위치 block_last = math.ceil(block_start + (block_size - 1)) return render_template( "list.html", datas=datas, limit=limit, page=page, block_start=block_start, block_last=block_last, last_page_num=last_page_num) @app.route("/view/<idx>") def board_view(idx): #idx = request.args.get("idx") if idx is not None: board = mongo.db.board data = board.find_one({"_id": ObjectId(idx)}) if data is not None: result = { "id" : data.get("_id"), "name" : data.get("name"), "title": data.get("title"), "contents":data.get("contents"), "pubdate":data.get("pubdate"), "view":data.get("view") } return render_template("view.html", result=result) return abort(404) @app.route("/write", methods=["GET", "POST"]) def board_write(): if request.method == "POST": name = request.form.get("name") title = request.form.get("title") contents = request.form.get("contents") print(name, title, contents) current_utc_time = round(datetime.utcnow().timestamp()*1000) board = mongo.db.board #있으면 리턴 없으면 board 생성 post = { "name" : name, "title": title, "contents": contents, "pubdate":current_utc_time, "view":0 } x = board.insert_one(post) print(x.inserted_id) return redirect(url_for("board_view", idx=x.inserted_id)) else: return render_template("write.html") if __name__ == "__main__": app.run(debug=True, host="0.0.0.0", port=9000) <script> function search(){ var v_search = document.getElementById("search").value; var v_keyword = document.getElementById("keyword").value; if(v_search=="" | v_keyword==""){ return false; } else { self.location.href = "{{url_for('lists')}}?search=" + v_search +"&keyword="+v_keyword; } } </script> {%if datas.count() >0 %} <table> <thead> <tr> <td>번호</td> <td>제목</td> <td>이름</td> <td>날짜</td> <td>조회수</td> </tr> </thead> <tbody> <!--반복구간 시작--> {% for data in datas %} <tr> <td>{{loop.index + ((page -1) * limit)}}</td> <td><a href="{{url_for('board_view', idx=data._id)}}">{{data.title}}</a></td> <td>{{data.name}}</td> <td>{{data.pubdate | formatdatetime}}</td> <td>{{data.view}}</td> </tr> {% endfor %} <!--반복구간 끝--> </tbody> </table> {%if block_start - 1 > 0%} <a href="{{url_for('lists', page= block_start - 1)}}">[이전]</a> {%endif%} {% for i in range(block_start , block_last + 1)%} {%if i > last_page_num %} {{ i }} {%else%} {% if i == page %} <b>{{ i }}</b> {%else%} <a href="{{url_for('lists', page=i)}}">{{i}}</a> {%endif%} {%endif%} {% endfor%} {%if block_last < last_page_num%} <a href="{{url_for('lists', page= block_last+1)}}">[다음]</a> {%endif%} <select name="search" id="search"> <option value="">검색대상</option> <option value="0">제목</option> <option value="1">내용</option> <option value="2">제목+내용</option> <option value="3">작성자</option> </select> <input type="text" name="keyword" id="keyword"> <input type="button" value="검색" onclick="search()"> {% else %} <h3>데이터 없음</h3> {% endif %} 강의와 관련있는 질문을 남겨주세요.• 강의와 관련이 없는 질문은 지식공유자가 답변하지 않을 수 있습니다. (사적 상담, 컨설팅, 과제 풀이 등)• 질문을 남기기 전, 비슷한 내용을 질문한 수강생이 있는지 먼저 검색을 해주세요. (중복 질문을 자제해주세요.)• 서비스 운영 관련 질문은 인프런 우측 하단 ‘문의하기’를 이용해주세요. (영상 재생 문제, 사이트 버그, 강의 환불 등) 질문 전달에도 요령이 필요합니다.• 지식공유자가 질문을 좀 더 쉽게 확인할 수 있게 도와주세요.• 강의실 페이지(/lecture) 에서 '질문하기'를 이용해주시면 질문과 연관된 수업 영상 제목이 함께 등록됩니다.• 강의 대시보드에서 질문을 남길 경우, 관련 섹션 및 수업 제목을 기재해주세요. • 수업 특정 구간에 대한 질문은 꼭 영상 타임코드를 남겨주세요! 구체적인 질문일수록 명확한 답을 받을 수 있어요.• 질문 제목은 핵심 키워드를 포함해 간결하게 적어주세요.• 질문 내용은 자세하게 적어주시되, 지식공유자가 답변할 수 있도록 구체적으로 남겨주세요.• 정확한 질문 내용과 함께 코드를 적어주시거나, 캡쳐 이미지를 첨부하면 더욱 좋습니다. 기본적인 예의를 지켜주세요.• 정중한 의견 및 문의 제시, 감사 인사 등의 커뮤니케이션은 더 나은 강의를 위한 기틀이 됩니다. • 질문이 있을 때에는 강의를 만든 지식공유자에 대한 기본적인 예의를 꼭 지켜주세요. • 반말, 욕설, 과격한 표현 등 지식공유자를 불쾌하게 할 수 있는 내용은 스팸 처리 등 제재를 가할 수 있습니다.