일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 토이프로젝트
- 배포
- Firebase
- vue
- nginx
- 뷰
- plugin
- 신상마켓
- jwt
- AWS
- javascript
- database
- react-query
- 프론트
- 로그인
- extension
- express
- 회고록
- PWA
- Git
- 플러그인
- 셋팅
- 기획
- react
- Docker
- vsCode
- 정리
- login
- vuex
- vue login
- Today
- Total
강디너의 개발 일지
Firebase realtime database pagination 삽질기 본문
목적
firebase database 특정 데이터를 '조건'에 맞춰 페이징 + 정렬하고 싶다.
- group/showGroup 아래의 데이터들을 likes/count가 높은 수 대로 맞춰서 정렬하고 싶다.
firebase database 생김새
아래 코드는 group/showGroup 아래 likes/count에 대해서 정렬하는 코드입니다.
하지만 정렬만 하는 기능일 뿐 페이징을 하지 못합니다.
firebase database 기본 쿼리에서는 페이징 기능을 따로 지원하지 않기 때문에 자체적으로 만들어야 합니다.
// group/showGroup 아래 likes/count 에 대해서 정렬
export function getOpenGroup() {
return firebase.database().ref('group/showGroup').orderByChild('likes/count');
}
// group/showGroup 목록의 key length를 가져오려고 만든 함수
export function getOpenGroupLength() {
return firebase.database().ref('group/showGroup');
}
https://firebase.google.com/docs/database/admin/retrieve-data?hl=ko
아래 코드는 초기값을 성정하는 코드입니다.
목록의 총길이를 저장 후, 정렬한 데이터를 가져옵니다.
const init = () => {
getOpenGroupLength()
.once('value', snapshot => {
// 길이 저장
groupLength.value += snapshot.numChildren();
// 최초 리스트 길이가 perPage 보다 작을 경우 최초 리스트 길이만 부르기
if (groupLength.value < perPage +1) perPage = groupLength.value -1;
getOpenGroup()
.limitToLast(perPage + 1)
.on("child_added", snapshot => {
getData(snapshot);
});
});
};
여기서 중요한 점은 limitToLast (또는 limitToFirst) perPage + 1로 해야 한다는 점입니다.
그 이유는 데이터를 1개 더 가져온 후 해당 key값, value값을 저장해서 다음 페이지의 시작점이 돼야 하기 때문입니다.
const getData = (snapshot) => {
if (!snapshot.val()) return;
tempArr.push(snapshot.val());
// 1번
tempKey.push(snapshot.key);
tempValue.push(snapshot.val().likes.count);
lastKey.value = tempKey[0];
lastValue.value = tempValue[0];
// 3번
if (groupLength.value < perPage + 1) {
isFinish.value = true;
openGroups.value.push(snapshot.val());
}
// 2번
if (tempArr.length === perPage + 1) {
tempArr.shift();
openGroups.value.push(...tempArr.reverse());
groupLength.value -= perPage;
}
};
예를 들어 페이지 한 개에 목록을 4개를 보여야 한다면
limitToLast 값을 5로 설정 후 받은 데이터를 temp에 넣어줍니다.
1번
그다음 맨 마지막 값을 lastKey, lastValue에 넣어줍니다. 여기서 tempKey [0], tempValue [0]을 뽑아간 것은 마지막 값을 firebase에서 첫 번째로 주기 때문입니다. (로그로 찍어보세요!!)
2번
원하는 목록보다 1개 더 받았으니깐 삭제시킵니다.
likes/count의 수가 높을수록 정렬하고 싶었기 때문에 limitToLast로 받은 후 tempArr를 reverse 해서 넘겼습니다.
그 후 총목록에서 내가 받은 만큼 빼줍니다.
3번
groupLength 변수에 목록의 총길이를 넣어놨었는데 groupLength 가 5보다 작으면 마지막 페이지란 뜻이니깐 종료시킨 후 temp 데이터를 삭제 없이 넘깁니다.
그다음 페이지를 부르는 코드입니다.
const getOpenGroupData = () => {
if (isFinish.value) return;
tempArr = [];
tempKey = [];
tempValue = [];
getOpenGroup()
.endAt(lastValue.value, lastKey.value)
.limitToLast(perPage + 1)
.on("child_added", snapshot => {
getData(snapshot);
});
};
endAt( lastValue, lastKey) 값을 넣어줘서 시작점을 알려줍니다.
예전에는 키값만 넣어줘도 된다더니... 둘 다 넣어줘야 합니다.
endAt 이 안 먹히는 줄 알고 엄청 개고생을... 했습니다.
아래 코드는 스크롤 최하단 or 버튼 클릭 시 목록이 더 나오는 코드입니다.
결과 코드
import {
ref,
onMounted,
watch
} from "@vue/composition-api";
import {
getOpenGroup,
getOpenGroupLength
} from '@/services/group';
export const openGroup = (perPage, page, isScroll = true) => {
const openGroups = ref([]);
let tempKey = [];
let tempValue = [];
let tempArr = [];
const groupLength = ref(0);
const lastKey = ref('');
const lastValue = ref(0);
const isFinish = ref(false);
const getData = (snapshot) => {
if (!snapshot.val()) return;
tempArr.push(snapshot.val());
tempKey.push(snapshot.key);
tempValue.push(snapshot.val().likes.count);
lastKey.value = tempKey[0];
lastValue.value = tempValue[0];
if (groupLength.value < perPage + 1) {
isFinish.value = true;
openGroups.value.push(snapshot.val());
}
if (tempArr.length === perPage + 1) {
tempArr.shift();
openGroups.value.push(...tempArr.reverse());
groupLength.value -= perPage;
}
};
const getOpenGroupData = () => {
if (isFinish.value) return;
tempArr = [];
tempKey = [];
tempValue = [];
getOpenGroup()
.endAt(lastValue.value, lastKey.value)
.limitToLast(perPage + 1)
.on("child_added", snapshot => {
getData(snapshot);
});
};
const init = () => {
getOpenGroupLength()
.once('value', snapshot => {
groupLength.value += snapshot.numChildren();
// 최초 리스트 길이가 perPage 보다 작을 경우 최초 리스트 길이만 부르기
if (groupLength.value < perPage +1) perPage = groupLength.value -1;
getOpenGroup()
.limitToLast(perPage + 1)
.on("child_added", snapshot => {
getData(snapshot);
});
});
};
const readMore = () => {
if (isFinish.value) return;
page.value += 1;
};
const scroll = () => {
if (!isScroll) return;
window.onscroll = () => {
let bottomOfWindow =
Math.max(
window.pageYOffset,
document.documentElement.scrollTop,
document.body.scrollTop
) +
window.innerHeight ===
document.documentElement.offsetHeight;
if (bottomOfWindow) {
page.value += 1;
}
};
};
watch(page, () => {
if (page.value === 1) return init();
getOpenGroupData();
});
onMounted(() => {
scroll();
});
return {
openGroups,
readMore,
isFinish,
};
};
https://github.com/DinnerKang/study_vue/blob/master/deali-music/src/composible/openGroup.js
- 5/27 수정
'Javascript > 삽질' 카테고리의 다른 글
javascript - JWT 로그인 및 세션 유지 (0) | 2021.02.07 |
---|---|
화면에 특정 DOM 이 보이는가? - InterSectionObserver API (4) | 2020.09.03 |
Firebase Database CRUD (0) | 2020.02.17 |
javascript - AWS Lambda 를 이용해서 크롤링하기 (0) | 2020.01.27 |
Vue - google OAuth2 로그인 및 Youtube 연동 (0) | 2020.01.20 |