iT邦幫忙

2022 iThome 鐵人賽

DAY 26
0
Modern Web

MERN Stack + Tailwind CSS - React 小專案實踐計畫系列 第 26

【Day 26】搜尋功能 - MongoDB Atlas Search

  • 分享至 

  • xImage
  •  

Atlas Search

在瀏覽器上登入 MongoDB,然後點擊專案 Database 的 Search 功能,接著選擇「Create Search Index」

https://ithelp.ithome.com.tw/upload/images/20221011/20152502hWk8wrkM5T.png

選擇「JSON Editor」格式

https://ithelp.ithome.com.tw/upload/images/20221011/20152502eam6DgLLnH.png

  • 左邊選擇要建立搜尋功能的資料庫及集合(bb-log → posts)
  • Index Name 維持預設 default(當然要改名稱也可以~)
  • JSON 內容不用調整,直接按下一步

https://ithelp.ithome.com.tw/upload/images/20221011/2015250247uIwp1GJ7.png

確認內容正確後,按下建立 Search Index

https://ithelp.ithome.com.tw/upload/images/20221011/201525025NBdDkuAZp.png

稍微等一下後就會看到建立好的 Search Index

https://ithelp.ithome.com.tw/upload/images/20221011/20152502lJNwoTXMP2.png

點擊名稱「default」→「Search Tester」,可以直接測試功能是否正常

https://ithelp.ithome.com.tw/upload/images/20221011/20152502aNuCZFkLE7.png

點擊右邊的「Edit Query Syntax」,可以看到以 mongoose 書寫的程式碼,接下來就是將這些加進我們的後端 API

https://ithelp.ithome.com.tw/upload/images/20221011/20152502bLk6J4vByL.png

新增 searchPost API

  • 取出路徑參數 req.params.keyword
  • 接著使用 MongoDB 聚合工具 Aggregate Framework ,使用 Model.aggregate() 並將剛剛的程式碼放進去
  • 這邊因為我們的搜尋內容包括中文,所以調整一下 text 的 query → 改成 (.*)${keyword}(.*) ,這樣就能順利搜尋中文的內容啦!
exports.searchPost = async (req, res, next) => {
    try {
        const { keyword } = req.params;

        const posts = await Post.aggregate([
            {
                $search: {
                    index: 'default',
                    text: {
                        query: `(.*)${keyword}(.*)`,
                        path: {
                            wildcard: '*',
                        },
                    },
                },
            },
        ]);

        res.status(200).json({
            status: 'success',
            data: {
                data: posts,
            },
        });
    } catch (err) {
        console.log(err);
        res.status(404).json({
            status: 'error',
        });
    }
};

記得要在 postRoutes.js 新增路徑

router.route('/searchPost/:keyword').get(postController.searchPost);

回到前端

  • api/index 新增 searchPost()
  • App.js 新增路徑 /search 並建立 <Search /> 頁面
  • Home.js 修改 handleSearch ,然後使用 useNavigate ,讓執行時會跳轉到 Search 頁面,並將 keyword 變數傳過去
import { useNavigate } from 'react-router-dom';

const handleSearch = () => {
    if (keyword.length < 1) {
        alert('搜尋關鍵字:請輸入至少 1 個字');
        return;
    }
    navigate(`/search`, { state: { keyword } });
};

<input> 使用 onKeyPress 來判斷使用者在輸入搜尋關鍵字時按下 Enter 就會執行 handleSearch

<input
    type="text"
    placeholder={'關鍵字'}
    value={keyword}
    onChange={(e) => setKeyword(e.target.value)}
    onKeyPress={(e) => (e.key === 'Enter' ? handleSearch() : null)}
    className="absolute w-2/5 h-10 rounded-md pl-10 focus:outline-0 focus:bg-yellow-700/5"
></input>

https://ithelp.ithome.com.tw/upload/images/20221011/20152502cR61Wwbgvb.png

Search.js 頁面

  • 複製 Home.js 來修改
  • 使用 useLocation 來取得從 Home.js 傳來的 keyword 變數,並設定為狀態變數 keyword 的初始值
import { useLocation } from 'react-router-dom';

const location = useLocation();
const [keyword, setKeyword] = useState(location.state.keyword ? location.state.keyword : '');
  • 從 api 引入 searchPost ,並在 useEffecthandleSearch 中使用
  • 增加 posts.length 判斷式,在找不到相關文章時提示使用者
{posts.length !== 0 ? (
    <Post data={posts} />
) : (
    <div className="">沒有符合條件的文章,試試其他關鍵字?</div>
)}

https://ithelp.ithome.com.tw/upload/images/20221011/20152502Lbel9u80F8.png

https://ithelp.ithome.com.tw/upload/images/20221011/20152502Wqgf3hfwna.png

頁面的呈現會像這樣子~ 這樣就大致完成搜尋文章的功能啦!

https://ithelp.ithome.com.tw/upload/images/20221011/20152502ulqc47jiBg.png

https://ithelp.ithome.com.tw/upload/images/20221011/20152502QfTwlQ9B4c.png

https://ithelp.ithome.com.tw/upload/images/20221011/201525029qa7biFV6D.png


上一篇
【Day 25】註冊 / 登入 Authentication(3) - 前端功能
下一篇
【Day 27】資料載入前… Loading 畫面
系列文
MERN Stack + Tailwind CSS - React 小專案實踐計畫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言