التصفية المتقدمة والتنقل بين الصفحات
متوسط
اعرف عوامل التصفية التي تطبقها الواجهة وتلك التي تطبقها أنت، وتنقّل بين الصفحات بكفاءة، واحفظ النتائج مؤقتًا لتوفير الطلبات.
عوامل التصفية في الواجهة
| نقطة الوصول | عوامل التصفية على الخادم |
|---|---|
/api/v1/metrics | city أو مستطيل (north وsouth وeast وwest)، وpast_days، وforward_days |
/api/v1/trends | city, metric, source (all, gathern, airbnb), days |
/api/v1/listings | city, limit, cursor |
/api/v1/estimate | الموقع وradiusKm وbedrooms وtypeId |
أما ما عدا ذلك، مثل مصدر العقار أو الحي أو التقييم أو فئة السعر، فتصفّيه في شيفرتك بعد الجلب.
تنقّل بين صفحات المدينة بكفاءة
استخدم limit=500، وهو الحد الأقصى، لتقليل عدد الطلبات، وتوقف عندما تصبح قيمة nextCursor هي null.
import { api } from "./jokerprice.mjs"; // helper from the quickstart
export async function allListings(city) {
const out = [];
let cursor = null;
do {
const page = await api("/api/v1/listings", { query: { city, limit: 500, ...(cursor ? { cursor } : {}) } });
out.push(...page.listings);
cursor = page.nextCursor;
} while (cursor);
return out;
}احفظ النتائج مؤقتًا ليوم واحد
تتغير العقارات ببطء. احفظ بيانات كل مدينة مرة يوميًا، وطبّق على الملف ما تشاء من عوامل التصفية.
import { existsSync, readFileSync, writeFileSync } from "node:fs";
export async function cachedListings(city) {
const file = city + "-" + new Date().toISOString().slice(0, 10) + ".json";
if (existsSync(file)) return JSON.parse(readFileSync(file, "utf8"));
const listings = await allListings(city);
writeFileSync(file, JSON.stringify(listings));
return listings;
}عامل تصفية قابل للتركيب
const where = {
source: s => l => l.source === s,
district: d => l => (l.district || "").toLowerCase().includes(d.toLowerCase()),
type: id => l => String(l.typeId) === String(id),
bedrooms: (min, max = min) => l => l.bedrooms >= min && l.bedrooms <= max,
price: (min, max) => l => l.nightly >= min && l.nightly <= max,
rating: min => l => (l.rating ?? 0) >= min,
reviews: min => l => (l.reviews ?? 0) >= min,
seenWithin: days => l => Date.now() - Date.parse(l.updatedAt) <= days * 86400000,
};
const all = (...tests) => l => tests.every(t => t(l));
const listings = await cachedListings("riyadh");
const picks = listings.filter(all(where.type(6), where.bedrooms(2, 3), where.price(300, 700), where.rating(9), where.reviews(10), where.seenWithin(14)));
console.log(picks.length, "matching listings");حدّد نطاق المؤشرات بالطريقة نفسها
لا يمكن تصفية المؤشرات حسب عدد غرف النوم أو النوع عبر الواجهة، لكن مستطيلًا يحيط بالعقارات التي أبقيتها يحصر الأداء في المنطقة نفسها.
const lat = picks.map(l => l.latitude), lng = picks.map(l => l.longitude);
const box = { north: Math.max(...lat), south: Math.min(...lat), east: Math.max(...lng), west: Math.min(...lng) };
const { metrics } = await api("/api/v1/metrics", { query: { ...box, past_days: 60 } });
console.log(metrics.maturity, metrics.past.occupancy);يجب ألا يكون المستطيل فارغًا (الجنوب أدنى من الشمال، والغرب أدنى من الشرق)، وألا يتجاوز عرضه 5 درجات.
قارن المصادر في الاتجاهات
for source in all gathern airbnb; do
curl -s -H "Authorization: Bearer $JOKERPRICE_API_KEY" \
"https://jokerprice.com/api/v1/trends?city=riyadh&metric=asking&source=$source&days=30" | jq -r '.trends.points[-1] | "\(.day) \(.value)"'
done