search.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. let express = require('express')
  2. let router = express.Router()
  3. let { Post, Thread, User, Category, Sequelize } = require('../models')
  4. const Errors = require('../lib/errors')
  5. router.get('/thread', async (req, res, next) => {
  6. try {
  7. let searchString = req.query.q
  8. let offset = +req.query.offset || 0
  9. let limit = 10
  10. /*
  11. Task is to find threads that either have the
  12. string in the title or in the content of the first post
  13. Method
  14. 1) Select first n items from each group (posts and threads), where n is the LIMIT,
  15. greater than id x, where x is previous OFFSET
  16. 2) Merge results from both, remove duplicates and sort
  17. 3) Select first n items from merged group
  18. 4) Set x as the last item from merged group
  19. */
  20. let threadTitles = await Thread.findAll({
  21. where: {
  22. name: { $like: '%' + searchString + '%' }
  23. },
  24. order: [ ['id', 'DESC'] ],
  25. include: [
  26. {
  27. model: Post,
  28. include: [{ model: User, attributes: { exclude: ['hash'] } }],
  29. where: {
  30. postNumber: 0
  31. }
  32. },
  33. { model: Category },
  34. { model: User, attributes: { exclude: ['hash'] } }
  35. ],
  36. limit,
  37. offset
  38. })
  39. let threadPosts = await Thread.findAll({
  40. order: [ ['id', 'DESC'] ],
  41. include: [
  42. {
  43. model: Post,
  44. include: [{ model: User, attributes: { exclude: ['hash'] } }],
  45. where: {
  46. postNumber: 0,
  47. content: { $like: '%' + searchString + '%' }
  48. }
  49. },
  50. { model: Category },
  51. { model: User, attributes: { exclude: ['hash'] } }
  52. ],
  53. limit,
  54. offset
  55. })
  56. let merged = [...threadTitles, ...threadPosts];
  57. let unique = [];
  58. merged.forEach(thread => {
  59. let includes = unique.filter(u => thread.id === u.id);
  60. if(!includes.length) unique.push(thread);
  61. });
  62. let sorted = unique
  63. .sort((a, b) => {
  64. return a.id - b.id;
  65. })
  66. .slice(0, limit);
  67. res.json({
  68. threads: sorted,
  69. offset: sorted.length ? sorted.slice(-1)[0].id : null,
  70. next: sorted.length < limit ? null : limit
  71. })
  72. } catch (e) { next(e) }
  73. })
  74. router.get('/user', async (req, res, next) => {
  75. try {
  76. let searchString = req.query.q
  77. let offset = +req.query.offset || 0
  78. let limit = 10
  79. let users = await User.findAll({
  80. where: {
  81. username: { $like: '%' + searchString + '%' }
  82. },
  83. order: [ ['username', 'DESC'] ],
  84. attributes: { exclude: ['hash'] },
  85. limit,
  86. offset
  87. })
  88. res.json({
  89. users,
  90. offset: users.length < limit ? null : offset + limit,
  91. next: users.length < limit ? null : limit
  92. })
  93. } catch (e) { next(e) }
  94. })
  95. module.exports = router