2014-04-08 10 views
1

나는 app과 같은 데이트 사이트에 가장 적합한 스키마가 무엇인지 알아 내려고하고 있습니다. 사용자는 목록을 가지고 있으며 (가능하면 많음) 다른 사용자 목록을 '좋아요'및 '싫어함'으로 볼 수 있습니다.MongoDB Array 쿼리 성능

현재 나는 likedBydislikedBy 배열에있는 다른 사람의 ID를 저장하고 있습니다. 사용자가 목록을 '좋아할'때, 목록 ID를 '좋아하는'목록 배열에 넣습니다. 그러나 나는 사용자가 목록을 좋아하는 시간 기록을 추적하고 싶습니다. 이것은 사용자의 '기록 목록'또는 데이터 분석에 사용됩니다.

find all active listings that this user has not liked or disliked before

find all the listings user X has liked in chronological order

내 현재 스키마가 '좋아'/ '싫어'선택의 사용자의 역사 :

나는 두 개의 별도의 쿼리를 수행해야합니다 :

listings 
    _id: 'sdf3f' 
    likedBy: ['12ac', 'as3vd', 'sadf3'] 
    dislikedBy: ['asdf', 'sdsdf', 'asdfas'] 
    active: bool 

이런 식으로 할 수 있을까요?

listings 
    _id: 'sdf3f' 
    likedBy: [{'12ac', date: Date}, {'ds3d', date: Date}] 
    dislikedBy: [{'s12ac', date: Date}, {'6fs3d', date: Date}] 
    active: bool 

나는 또한 choices에 대한 새 컬렉션을 만들려고했습니다.

choices 
    Id 
    userId   // id of current user making the choice 
    userlistId  // listing of the user making the choice 
    listingChoseId // the listing they chose yes/no 
    type 
    date 

은 내가 find all active listings that this user has not liked or disliked before을 할 때 다른 컬렉션 이러한 선택을 데의 성능 의미의 확실하지 않다.

어떤 통찰력이라도 대단히 감사하겠습니다!

+0

실제로 사용법을 말할 의도가 없을 때 어떤 종류의 스키마를 사용하는지에 대해 누구나 언급하기가 어렵습니다. 아마도 타임 스탬프 정보를 추가해야하는 이유가있을 수 있습니다. 공유 한 경우 질문에 사용하려면 답할 것이 있습니다. –

+0

감사합니다. @NeilLunn, 이해하기 쉽게하기 위해 다시 작성했습니다. 기본적으로 나는 선택한 모든 목록과 'likes'와 'dislikes'에 대한 사용자의 기록을 얻기위한 별도의 쿼리를 찾기 위해 쿼리를 실행할 수 있어야합니다. – SkinnyGeek1010

답변

5

글쎄, 분명히 여기에 제시된 사례에 대한 추가 사용 패턴이 제대로 작동하도록 "목록"문서에 이러한 것을 포함시키는 것이 좋습니다. 그걸 염두에두고 버릴 이유가 없습니다.

{ 
    "_id": "sdf3f", 
    "likedBy": [ 
     { "userId": "12ac", "date": ISODate("2014-04-09T07:30:47.091Z") }, 
     { "userId": "as3vd", "date": ISODate("2014-04-09T07:30:47.091Z") }, 
     { "userId": "sadf3", "date": ISODate("2014-04-09T07:30:47.091Z") } 
    ], 
    "dislikedBy": [ 
     { "userId": "asdf", "date": ISODate("2014-04-09T07:30:47.091Z") }, 
     { "userId": "sdsdf", "date": ISODate("2014-04-09T07:30:47.091Z") }, 
     { "userId": "asdfas", "date": ISODate("2014-04-09T07:30:47.091Z") } 
    ], 
    "active": true 
} 

하나 개 잡기가 있다는 것을 제외하고는 모두 잘 괜찮 :하지만 명확하게

, 당신이 원하는 것처럼 보이는 구조는 다음과 같은 것입니다. 두 개의 배열 필드에이 내용이 있으므로 두 필드 모두에 대해 색인을 만들 수는 없습니다. 이는 하나의 배열 유형의 필드 (또는 다중 키) 만 복합 인덱스에 포함될 수있는 제한 사항입니다.

그래서 첫 번째 쿼리가 인덱스를 사용 할 수없는에 명백한 문제를 해결하기 위해, 당신은 대신이 같은 구조 것입니다 :

db.post.ensureIndex({ 
    "active": 1, 
    "votes.userId": 1, 
    "votes.date": 1, 
    "votes.type": 1 
}) 
:

{ 
    "_id": "sdf3f", 
    "votes": [ 
     { 
      "userId": "12ac", 
      "type": "like", 
      "date": ISODate("2014-04-09T07:30:47.091Z") 
     }, 
     { 
      "userId": "as3vd", 
      "type": "like", 
      "date": ISODate("2014-04-09T07:30:47.091Z") 
     }, 
     { 
      "userId": "sadf3", 
      "type": "like", 
      "date": ISODate("2014-04-09T07:30:47.091Z") 
     }, 
     { 
      "userId": "asdf", 
      "type": "dislike", 
      "date": ISODate("2014-04-09T07:30:47.091Z") 
     }, 
     { 
      "userId": "sdsdf", 
      "type": "dislike", 
      "date": ISODate("2014-04-09T07:30:47.091Z") 
     }, 
     { 
      "userId": "asdfas", 
      "type": "dislike", 
      "date": ISODate("2014-04-09T07:30:47.091Z") 
     } 
    ], 
    "active": true 
} 

이이 양식을 포함하는 인덱스를 할 수 있습니다

실제로 사용 패턴에 따라 몇 가지 인덱스가 필요할 수 있지만 포인트에 이제는 사용할 수있는 인덱스가있을 수 있습니다.

당신이 쿼리의이 양식을 가지고 첫 번째 경우를 커버 :

명확 각 사용자에 대한 추천하고 싫어하는 옵션 모두를하지 않을 것을 고려 의미가
db.post.find({ "active": true, "votes.userId": { "$ne": "12ac" } }) 

. 해당 색인의 순서에 따라 최소 활성 상태는 필터링 조건을 부정적인 조건으로 모두 스캔해야하기 때문에 필터링 할 수 있습니다. 어떤 구조로든 그럴 수 있습니다.

다른 경우에는 userId가 날짜 이전의 색인에 있고 첫 번째 요소로 사용되기를 원할 것입니다. 그런 다음 쿼리가 매우 간단합니다 :

db.post.find({ "votes.userId": "12ac" }) 
    .sort({ "votes.userId": 1, "votes.date": 1 }) 

하지만 갑자기 뭔가를 잃었다 궁금 할 수, "좋아"와 "싫어"의 카운트가 전에 배열의 크기를 테스트 한 쉬웠다 받고 있지만, 이제는 조금 다릅니다. 아니 집계하여 해결할 수없는 문제 : 그룹화 _id을 유지하고 "좋아"와 "싫어의 수를 평가하기 위해 문서의 중요한 부분을 저장할 수있는 어떤 실제 사용 형태

db.post.aggregate([ 
    { "$unwind": "$votes" }, 
    { "$group": { 
     "_id": { 
      "_id": "$_id", 
      "active": "$active" 
     }, 
     "likes": { "$sum": { "$cond": [ 
      { "$eq": [ "$votes.type", "like" ] }, 
      1, 
      0 
     ]}}, 
     "dislikes": { "$sum": { "$cond": [ 
      { "$eq": [ "$votes.type", "dislike" ] }, 
      1, 
      0 
     ]}} 
]) 

그래서를 "쉬운 방법으로.

같은 항목에서 싫어하는 항목으로 변경하는 작업은 단일 원자 업데이트로 수행 할 수도 있습니다.

할 수있는 일이 훨씬 더 많지만 주어진 이유로이 구조를 선호합니다.

+0

고마워요! 이것은 정말 도움이됩니다! – SkinnyGeek1010

+0

왜 이것이 더 많은 upvotes를받지 못했습니까? 슈퍼 명확한 대답 – spartikus