Help with Queries

I’m working on learning AdonisJS better and am working on a project while I learn.

The project is a social-like clone and I’m attempting to pull in only users I follow in an activity feed showing their user photo only one time and then only showing their four most recent post.

However what is happening is I am only getting back the first four post of the very first user in the system.

So my current issues are:

  1. Showing only users I follow
  2. Limiting it to showing only their first four most recent postings
  3. Only showing their User photo one time.

Here is my current code I wrote in the backend.

FollowedUserPosts: async (_, __, context) => {
          let auth = context.auth;
          try {
              await auth.check()
              const users = await Database.table('users').select('*')
              for (let i=0; i<users.length; i++) {

                // Find users I follow
                const myfollows = await Follow.query()
                .where('follower_uuid', '=', user.uuid)
                .where('follow_uuid', '=', user.follow_uuid)
                .fetch()

                  // Add profile Image
                  const photos = await PhotoUpload.query()
                  .where('belongsTo', '=', users[i].uuid)
                  .where('type', '=', 'userPhoto')
                  .fetch()
                  if (photos.rows.length >0) {
                      users[i].photo = photos.rows[0].name
                  }
              }

              // posts list from posts table
              const posts = await Database.table('posts').select('*').limit(4)

              // loop posts
              for (let i=0; i<posts.length; i++) {

                  // user posted current post
                  const user = users.filter((value) => value.id === posts[i].op)[0];

                  posts[i].opFirstName = user.firstname;
                  posts[i].opLastName = user.lastname;
                  posts[i].opPhoto = user.photo;

                  // Add post images
                  const photos = await PhotoUpload.query()
                  .where('belongsTo', '=', posts[i].uuid)
                  .where('type', '=', 'post')
                  .fetch()

                  posts[i].photos = photos.rows

              }

              return posts

          } catch (error) {
              throw new Error('Missing or invalid jwt token')
          }
      },

Then this is my frontend code for looping through it:

       <ng-container id="followed-user-row"  >
          <div id="follower-holder"*ngFor="let item of FolUserPosts">
          <div id="act-avatar">
              <div id="useraccountpic">
                  <img width="60" height="60"src="http://{{appurl}}:3333/uploads/{{item.opPhoto}}">
              </div>
          </div>
          <div id="act-feed">
            <div id="act-col">
              <div id="act-item-box" *ngFor="let photo of item.photos" (click)="gotoPost(item.uuid)">
                <div id="posttitle">{{item.title}}</div>
                <div id="act-feed-item">
                    <img src="http://{{appurl}}:3333/uploads/{{photo.name}}">
                </div>
                
              </div>
            </div>
          </div>
        </div>
        <!-- <div style="clear:both;"></div> -->
        </ng-container>      

Any help would be appreciated as well as any really good training video references for understanding how to write the node query backend code better.

1 Like

Hmm, most likely you won’t want to loop over ALL the users you have. What if project goes viral and you end up with milion users. Then you have a lot of DB requests happening :slight_smile:

If this is in controller, then it can be simplified:

// from
FollowedUserPosts: async (_, __, context) => {
// to
async FollowedUserPosts({ auth }) {

To make controller code little bit nicer you can move that

await auth.check()

Into route middleware https://adonisjs.com/docs/4.1/authentication#_auth_middleware

I don’t really get where user comes from, but I assume it is logged in user.
You could simplify it even more with Lucid models and relations

// You should be able to simplify it down to something like this:
// It should handle all the logic you have currently
// But you need to set up relations for it
async FollowedUserPosts ({ auth }) {
    return auth.user.query()
        // Relation in User.js
        .with('follow') 
        // Photo is defined relation in Follow.js
        .with('follow.photo', (builder) => { 
            builder.where({ type: 'userPhoto' })
        })
        // Posts is defined relation in Follow.js
        .with('follow.posts', (builder) => { 
            builder.limit(4).with('photo')
        })
}

And to answer question about problem in current code:

It is because of that:

posts[i].opFirstName = user.firstname;
posts[i].opLastName = user.lastname;
posts[i].opPhoto = user.photo;

You loop over all posts and add signed in user variables as post variables

1 Like

I’ve tried your solution however i just get null now in my frontend…

For such simplification you must define relations in models and there might be some typos since I wrote it in here.

Take a look at:
https://adonisjs.com/docs/4.1/lucid
and
https://adonisjs.com/docs/4.1/relationships

Yeah not sure yet how to do that even with the documentation. I’m trying to keep things as simple as possible right now for me to understand. My current solution works it just only shows me the first user first 4 post and repeats their userphoto for each post. I’m simply trying to understand how to only show the last 4 post for every user the currently logged in user follows and only show the user photo one time. So this is a difficult query /function for me to even understand how to go about writing.

For getting only last n rows you can use combination of orderBy and limit:

query().orderBy('id', 'desc').limit(n);

For photos you could add if and check if i === 0 which would mean that you are dealing with first post and add image only then