简体   繁体   中英

Display parent id with many-to-many relationship

I have a relationship many-to-many. I need to fetch all tags with parent id. For example it can look like this:

[
   { article_id: 1, id: 1, name: "tag 1" },
   { article_id: 1, id, 2, name: "tag 2" },
   { article_id: 2, id: 1, name: "tag 1" }
]

Look that tag 1 is two times for two articles. Propably I can make loop inside loop but it doesn't look proffesional. Could you show me the best solution of this problem?

@Edit: I created this code:

public function articles(){
    $article = [];
    $allArticles = Articles::all();
    foreach($allArticles as $key => $a){
        $obj = new \stdClass();
        foreach($a->tags as $t){
            $obj->article_id = $a->id;
            $obj->name = $t->name;
            array_push($article, $obj);
        }

    }


    return json_encode($article);
}

But it doesn't work like I want. It display only one tag for one article, not all. Any idea?

Don't quite understand what you are trying to achieve via the code snippet you have provided. However, as per the opening line of your question if you want to retrieve all tags with associated articles' ids then you can try the below

$tags = Tag::with('articles')
    ->get()
    ->map(function($tag) {
        $tag->articleIds = $tag->articles->pluck('id');
        unset($tag->articles);
        return $tag;
    });

This will give you an output like

[
   { id: 1, name: "tag 1", articleIds: [1,2] },
   { id, 2, name: "tag 2", articleIds: [1] },
]

If you want it other way around ie get the article with associated tags

$articles = Article::with('tags:id,name')
    ->get()
    ->map(function($article) {
        $object = new \StdClass;
        $object->article_id = $article->id;
        $object->tags = $article->tags;
        return $object;
    });

Which will give you an output like

[
   { article_id: 1, tags: [{id: 1, name: "tag 1" }, {id, 2, name: "tag 2"}] },
   { article_id: 2, tags: [{id: 1, name: "tag 1" }]},
]

Another way is do a join query which will return multiple rows for each article based on no. of tags assigned

$articles = DB::table('articles as a')
            ->select(['a.id','a.name','t.name as tag'])
            ->join('article_tags as at', 'a.id', '=', 'at.article_id')
            ->join('tags as t', 't.id', '=', 'at.tag_id')
            ->get();

so this way you don't need extra loop and no extra queries( N+1 ) will be fired to fetch related tags.

As per docs Relationship Methods Vs. Dynamic Properties

Dynamic properties are "lazy loading", meaning they will only load their relationship data when you actually access them. Because of this, developers often use eager loading to pre-load relationships they know will be accessed after loading the model. Eager loading provides a significant reduction in SQL queries that must be executed to load a model's relations.

If you still want to go with loop approach so atleast use eager loading like

$allArticles = Articles::with('tags')->all();

But still it will fire more than one query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM