Laravel Éloquent Modèle de requête personnalisés sélectionner/entrer/de commande

J'ai des modèles dits de Post, et PostView. Un Poste peut avoir de nombreuses PostViews. J'ai besoin d'obtenir un paginé liste des articles commandés par le comte de PostViews créé au cours des 30 derniers jours.

Je peux le faire à l'aide de withCount:

// works but S L O W
$posts = Post::withCount(['views' => function($query) {
            $query->where('post_views.created_at', '>=', 'DATE_ADD(CURDATE(), INTERVAL -30 DAY)');
         }])
         ->orderBy('views_count')
         ->paginate(10);

Toutefois, cela génère une requête qui est vraiment lent, prenant ~24 secondes.

À l'aide de matières sql je peux obtenir des résultats corrects beaucoup plus efficacement, comment puis-je tourner que dans le paginé modèle de la collection?

Cela génère la requête appropriée pour saisir les 10 premiers, mais la collection est vide. Je suppose qu'il a quelque chose à voir avec le selectRaw

$posts = Post::selectRaw('posts.*, count(post_views.id) as views_count')
           ->join('post_views', function($join) {
                $join->on('posts.id', '=', 'post_views.post_id')
                   ->where('post_views.created_at', '>=', 'DATE_ADD(CURDATE(), INTERVAL -30 DAY)');
            })
            ->groupBy('posts.id')
            ->orderBy('views_count', 'DESC')
            ->take(10)
            ->get();

Si j'exécute la requête qui génère directement dans mysql j'obtiens les résultats suivants: (remarque tronqué à des postes.id pour des raisons de concision)

mysql> select posts.id, count(post_views.id) as views_count from `posts` inner join `post_views` on `posts`.`id` = `post_views`.`post_id` and `post_views`.`created_at` >= DATE_ADD(CURDATE(), INTERVAL -30 DAY) group by `posts`.`id` order by `views_count` desc limit 10;
+--------+-------------+
| id     | views_count |
+--------+-------------+
| 150277 |          22 |
|  43843 |           6 |
| 138789 |           4 |
| 180565 |           4 |
|  50555 |           3 |
|   2679 |           3 |
| 188572 |           3 |
| 217454 |           3 |
| 136736 |           3 |
| 126472 |           2 |
+--------+-------------+
10 rows in set (1.26 sec)

Toute aide est appréciée, merci.

0
2019-09-18 07:34:06
source
3 réponses

Je ne sais pas pourquoi tout le monde est d'avoir de tels de la difficulté avec cette question, c'est parfaitement clair, malheureusement, il est aussi difficile de faire ce que vous voulez parce que python utilise implicite des types de données, et c'est rare. Par conséquent, tous les arguments de ligne de commande sont transmis à python comme des chaînes de caractères.

Je voudrais vérifier pour les détails:

https://www.tutorialspoint.com/python/python_command_line_arguments.htm

mais le tldr est d'avoir à l'intérieur de votre script python:

import sys

eps = int(sys.argv[sys.argv.index('eps')+1])
minpts = True if '-minputs' in sys.argv else False
…

Évidemment, ce n'est pas l'idéal, ou jolie, mais il est rapide et facile. Alternativement, vous pouvez utiliser le argparser de la bibliothèque:

https://docs.python.org/3/library/argparse.html

Pour plus robuste et la convivialité de la solution. Espérons que cette aide

A.

Edit: J'ai été absent de la " autour d'eps

+0
2019-09-18 07:52:29

Arguments De Ligne De Commande

import sys

imprimer 'version', sys.version

La première ligne permet d'importer une bibliothèque appelée sys, qui est l'abréviation de "système". Il définit les valeurs comme le sys.version, qui décrit la version de Python, nous sommes en cours d'exécution. Cette commande indique à l'interpréteur python installé sur votre machine pour exécuter le programme sys-version.py à partir du répertoire courant.

Voici un autre script qui fait quelque chose de plus intéressant:import sys print 'sys.argv is', sys.argv

+0
2019-09-18 07:52:29

Vous n'avez pas rendu le TimesPlaces/AgainstWhoms, de sorte que les données perdre, car elles ne sont pas dans le formulaire de collecte .

Si vous souhaitez modifier le TimesPlaces/AgainstWhoms , vous pouvez rendre comme :

@for (int i = 0; i < Model.TimesPlaces.Count; i++)
{
    <tr>
        <td>
            @Html.TextBoxFor(model => model.TimesPlaces[i].IncidentDate)
        </td>
        <td>
            @Html.TextBoxFor(model => model.TimesPlaces[i].IncidentLocation)
        </td>

    </tr>
}

Si vous ne voulez pas de les modifier , vous pouvez utiliser le champ caché :

@for (int i = 0; i < Model.TimesPlaces.Count; i++)
{

    @Html.HiddenFor(model => model.TimesPlaces[i].IncidentDate)
    @Html.HiddenFor(model => model.TimesPlaces[i].IncidentLocation)
}

Mais c'est mieux de l'éviter . Si vous ne voulez pas éditer , je préfère de requête de base de données avec l'ID de nouveau pour la mise à jour des dossiers , et d'éviter de diffuser des données de grande taille dans une demande .

+0
2019-09-18 09:53:20

Voir d'autres questions sur les étiquettes