ugrás a tartalomhoz

[Lekérés] Követett felhasználók "feed"

sandrosdj · 2014. Okt. 6. (H), 15.55
Sziasztok!

Egy ideje próbálok összerakni egy olyan lekérést, amely több táblából képes egyszerre kiolvasni adatokat.
Ez leginkább a facebook tickeréhez, vagy a spotify action bar-jához hasonlítható.

A felhasználók az users táblában, a követések a favs táblában, a listázandó dolgok pedig a posts és comments táblában találhatóak.

Táblákról:
users: userId, userName
favs: favId, favUser, favUser2, favStatus (0,1), favTime (INT 10)
- az user a követő, az user2 pedig, hogy kit
- status = 1: követi, status = 0: már nem követi
- time: ekkor történt a követés/kikövetés
posts: postId, postTitle, postTime (INT 10)
comments: commentPost, commentText, commentTime (INT 10)


No, itt tulajdonképpen az kellene, hogy ha futtatom a fetch_assoc() függvényt, akkor listázódjanak sorban a posztok és kommentek pl.: $data['type'] = (comment ? post? ), $data[userName], $data[content] = (maga a komment vagy a post címe), $data[time] = időpont.

Rengeteget gondolkodtam raja, de semmi működő lekérést nem sikerült még összeeszkábálni.
Már azzal is előrébb lennék, ha külön a kommentek és posztok számára lenne lekérés, amiket majd egy tömbbe rendezek.

A gondot a követések (favs) tábla okozza, mivel több sor tartozhat valakihez (status).

Nem kérem, hogy komplett megoldással álljon elő valaki, csak valami útmutatásra lenne szükségem. Dokumentációkat olvastam, de ilyenre megoldást még nem találtam és bevallom, hogy nincs sok időm rá (uni) (a lekérés saját használatra kell, nem feladat).

Előre is köszönöm a segítséget! :)
 
1

Ha nem teszed bele az

rrd · 2014. Okt. 6. (H), 23.44
Ha nem teszed bele az adatbázisba a kapcsolatokat akkor sose fogod tudni lekérdezni. Mármint a post és a komment esetén. Egyébként JOIN kell neked. Valami ilyesmi SELECT * FROM users, favs WHERE users.userId = favs.favUser
Legalábbis ha a favUser az a user id és nem a név. Ha a név van ott akkor olvasd el mi az a normalizálás.
2

union

szabo.b.gabor · 2014. Okt. 7. (K), 08.24
Az a lényeg, hogy minden lekérés ugyanolyan típusú mezőket adjon, utána már unionozhatod a részeket és ezeket így együtt már tudod rendezni.
(SELECT ize AS id, bigyo AS happened, 'valami' AS tipus FROM valami)
UNION
(SELECT abc AS id, dfsd AS happened, 'zz' AS tipus FROM zz)
UNION
(SELECT qwer AS id, yuip AS happened, 'sdf' AS tipus FROM sdf)
ORDER BY happened
Valami ilyesmi, lehet hogy a zárójelekkel még játszani kell, vagy a union-os részt () AS tablanev-en belülre tenni és fölé még egy selectet rakni.
3

Csináltam tesztként egy

sandrosdj · 2014. Okt. 7. (K), 20.37
Csináltam tesztként egy ilyet:
(SELECT playedSong, playedOn AS `time` FROM plays WHERE playedBy = 29) UNION (SELECT pitemSong, pitemAdded AS `time` FROM playlistItems WHERE pitemAddedBy = 29) ORDER BY `time` DESC
(A 29 és 11 értékeknek maguktól kellene odakerülniük a követés szerint. Bővebben: lent a Problem 2.)

PHP:
while ($data = $query->fetch_assoc())
	echo (isset($data['playedSong']) ? 'PS:'.$data['playedSong'] : 'LI:'.$data['pitemSong'])."<br/>";
Problem 1: Külön-külön a select-ek nagyon jól működnek (PS és LI), de ha a fent látható lekérést használnom (unionnal), akkor csak PS-ek vannak.

Problem 2: Plusz amit még nem tudok, hogy hogyan lehetne belefoglalni a lekérésbe azt, hogy csak a követetteké jelenjen meg. A problémát az okozza - mint említettem -, hogy egy felhasználónál több sor is van.

Pl.
id - user - user2 - status - time esetén
1, 2, 1, 10000000 <- követi
1, 2, 0, 11000000 <- már nem
1, 2, 1, 12000000 <- megint követi

Ezt INNER JOIN-nal próbáltam, de csak az első sort veszi figyelembe (id-t nézve), akármi lehet utána.


Mellékesen: Az UNION-os problémát ki lehet kerülni külön lekérésekkel, így csak a Problem 2 marad. Ebben az esetben kimenet + idő kerülne egy tömbbe, amit idő szerint lehetne rendezni.

A mellékes megoldást próbálva eddig jutottam:
SELECT songId, playedBy, userName FROM plays, (SELECT * FROM following WHERE fowUser = 29 AND fowUser2 = playedBy ORDER BY fowTime DESC LIMIT 1) AS followed INNER JOIN songs ON songId = playedSong INNER JOIN users ON userId = playedBy WHERE fowStatus = 1 ORDER BY playedOn
ilyen hibával: Unknown column 'playedBy' in 'where clause'
4

Solution 1

szabo.b.gabor · 2014. Okt. 8. (Sze), 08.33
Szerintem az 1es problémára annyi a megoldás, hogy elnevezed a playedSong, pitemSong mezőket is, ugyanolyanra és melléjük raksz egy típus mezőt.
(SELECT playedSong AS song, playedOn AS `time`, 'playedSong' AS tipus 
FROM plays 
WHERE playedBy = 29) 
UNION 
(SELECT pitemSong AS song, pitemAdded AS `time`, 'pitemSong' AS tipus 
FROM playlistItems 
WHERE pitemAddedBy = 29) 
ORDER BY `time` DESC
A problem2-t kicsit kifejthetnéd, bár azt hiszem értem. Követek valakit, addig megjelennek az eseményei, majd abbahagyom, ekkor nem jelennek már meg, de a régiek látszódnak továbbra is, majd újra elkezdem követni és akkor megint jönnek a dolgai. Így van?
5

Follow status adott

szabo.b.gabor · 2014. Okt. 8. (Sze), 08.52
Follow status adott időpontban.

SELECT fowUser,fowUser2,followStatus
FROM following
WHERE fowUser = 29 AND fowUser2 = 41 AND time <= time
ORDER BY time DESC
LIMIT 1

Ugye ezt kellene összejoinolni a dalok soraival, csakhogy itt a fowUser2 és a time a dalok soraiból jön. Érzésre nem fog menni.

google mit mond erre?

Itt valami 'correlated subquery'-ről volna szó. Első ránézésre nem nagyon megy a dolog, de hajrá, olvasgass utána.

Szerintem valami külön tábla volna esetleg jó, amibe feldolgozod az adatokat és eltárolod az eredményt. Vagy ugyanez programból.
6

Solution 2 (?)

szabo.b.gabor · 2014. Okt. 9. (Cs), 05.57
Megkaphatók egy felhasználó által adott időpontban követett felhasználók subquery nélkül, hogy ha a following táblában nem időpontot, hanem intervallumot használsz. Így igazából a statuszra sincs szükség, csak azokat az intervallumokat tárolod amikor követte. Ha még nem ért véget egy adott intervallum, akkor az intervallum vége NULL.
[table following]
-id_following (pk)
-id_user
-id_followed
-start
-end
Adott időpontban követett felhasználók.
SELECT id_followed 
FROM following 
WHERE start <= time AND (end > time OR end IS NULL)
Played_song-ra join (a kezdetre érdemes egy szűrés berakni, hogy kevesebb adattal dolgozzon..):
SELECT played_song, played_on, played_by
FROM plays AS p INNER JOIN following AS f ON
f.id_user = 29 AND p.played_on > 1281232332 AND f.start <= p.played_on AND (f.end > p.played_on OR f.end IS NULL)
ORDER BY played_on, played_by --vagy id_plays
Ez szerintem így már működhet, persze nem próbáltam ki egy query-t sem.
7

Tökéletes

sandrosdj · 2014. Okt. 10. (P), 00.37
Ez tökéletes. Hegesztettem rajta egy kicsit (a played_on értékének ellenőrzését nem láttam érdekesnek, mivel amúgy is a követés intervallumához viszonyítva jönnek ki a dolgok, valamint GROUP BY-jal megcsináltam, hogy egy elem csak egyszer jelenjen meg.

A többi tevékenységet külön lekérésekkel kapom meg, amiket összerakok egy tömbbe, így lesz a különálló "tevékenységekből" összefüggő dolog.

UNION-nal mindenképpen kísérletezni fogok még.

Valójában nem is bonyolult a megoldás, csak én képzeltem bele extrém dolgokat. Ebből is látszik, hogy van még hova fejlődni.


Köszönöm!
/ ha Debrecenben vagy/leszel, meghívlak egy sörre /

Up: a group by mégsem jó (nem valós dolgok jönnek ki), de ezt muszáj lesz megoldanom magamtól. :)
8

Szívesen.

szabo.b.gabor · 2014. Okt. 10. (P), 05.28
Szívesen.
9

Valójában mégsem jó. Pár óra

sandrosdj · 2014. Okt. 10. (P), 20.11
Valójában mégsem jó.
Pár óra alvás után elővettem átnézni, hogy mégis hogyan válassza el a felhasználókat a dolog.


Ugye benne van kritériumként, hogy fowUser = 29, tehát elméletileg csak azok a sorok vannak lekérve, ahol ez 29, mégis látom azokat a sorokat, amiknél a playedBy 29.
Gondoltam, hogy az lehet a hiba, hogy követem magam, de nem.

Mikor csak magamat követem, akkor jól jelennek meg a dolgok.
Jelen esetben látom a saját dolgaimat is annak ellenére, hogy nem követem magam és mindenből kettő van egymás után.

A lekérés így néz ki:
SELECT songTitle, userId, userName, playedSong  
FROM plays AS p INNER JOIN following AS f ON  
f.fowUser = 29 AND f.fowStart <= p.playedOn AND (f.fowStop > p.playedOn OR f.fowStop IS NULL) 
INNER JOIN songs ON songId = p.playedSong INNER JOIN users ON userId = p.playedBy
ORDER BY playedOn DESC LIMIT 40
Ezt orvosolni lehetne WHERE playedBy != 29 kritériummal, de ez így túl egyszerű lenne.
10

Lehet félre kellene tenned a gépet a hétvégére..

szabo.b.gabor · 2014. Okt. 10. (P), 21.54
..és kicsit kimenni a napra, meg a friss levegőre.

A following táblában leszűröd magadra és időpontra, de a követett felhasználó id-je semmilyen kritériumban nem jelenik meg. Ígyhát.. ez a lekérdezés kb annyit csinál, hogy amikor követtél bárkit, abban az időszakban játszott dalokat listázza, de ez nem is fontos..

;)