Vue3+node.js encapsulates MongoDB find, and the query object can be passed in to realize multi-condition, date and time range query

Not much nonsense, just dry goods, and the explanation is simple and easy to understand.

Note: The focus is on front-end and back-end linkage to realize multi-field filtering search queries. The process is relatively complete from the back-end connection to the database to the front-end DOM component binding data.

node>db>mongodb.js: connect to the database

const { MongoClient } = require('mongodb')

// Connection URL: change localhost to 127.0.0.1, default port 27017
const url = 'mongodb://127.0.0.1:27017'
const client = new MongoClient(url)

// Database Name
const dbName = 'wechat'

// Use connect method to connect to the server
client. connect()
console.log('Connected successfully to mongoDB server')
const db = client. db(dbName)

node>db>mongodb.js: package find

Pay attention to the two parts of formatting date time and formatting $in, which is a bit confusing…

// Encapsulation: query document
// query: the params object returned by the front-end axiosInstance
const findDoc = function (query, document) {
  return new Promise(async (resolve, reject) => {
    // Exclude empty objects? The front end may pass an empty object and cause an error
    let queryData = {} // pDateStr is replaced by dateStr
    let $and = [] // Save the date and time range query condition object, and other query condition objects can also be saved
    let startDate = {}
    let endDate = {}
    for (const key in query) {
      if (query[key].length > 0) {
        // Remove []: the front end may return an array with [] in the index
        let newKey = key. replaceAll('[]', '')
        // Convert newKey to lowercase
        let str = newKey.toLowerCase()
        if (str. includes('day') || str. includes('date') || str. includes('time')) {
          // Use new Date() to format it into standard time, and the database can be compared normally
          startDate[newKey] = { '$gte': new Date(query[key][0]) }
          endDate[newKey] = { '$lte': new Date(query[key][1]) }
          $and.push(startDate)
          $and.push(endDate)
        } else {
          queryData[newKey] = query[key] // formula: box index key-value pair
        }
      }
    }
    // Format query condition: return a string that conforms to the syntax of the MongoDB query condition
    const queryStr = JSON. stringify(queryData)
    const newStr1 = queryStr.replaceAll('[', '{"$in":[') // Multiple selection: construct multi-value query submission
    const newStr2 = newStr1.replaceAll(']', ']}') //Multiple selection: construct multi-value query submission
    let newQueryObj = JSON.parse(newStr2) // Format the string and then parse it into an object: there may be errors...
    // If the array is not empty, hang it into the query condition object
    if ($and. length > 0) {
      newQueryObj['$and'] = $and
    }
    // The first parameter of find: it is actually a JSON object. Note that the date has been formatted into standard time, and the corresponding mongodb field must be in date format
    await db.collection(document).find(newQueryObj).toArray()
      .then((res) => {
        if (res. length == 0) {
          resolve({
            status: 202,
            message: 'No data found! ',
            data:res
          })
        }
        // Get success: directly return the result
        resolve({
          status: 200,
          message: 'find document successfully!',
          data:res
        })
      })
      .catch((err) => {
        return reject({
          status: 203,
          message: 'Failed to find data from MongoDB, please check the query conditions! ',
          data: err
        })
      })
  })
}

node>db>mongodb.js: expose method function

This js file defines the common methods and functions of MongoDB addition, deletion, modification and query, so it is exposed in the following form:

module.exports = { findDoc, findOne, insertDoc, deleteDoc, updateDoc, distinctField }

node>router>index.js: import and use

Very simple call, no need to add another layer of module

const { findDoc } = require('../db/MongoDB')
router.get('/mongo/task/find', async (ctx) => {
  ctx.body = await findDoc(ctx.request.query, 'task')
})

vue3>src>api: call api and pass parameters

For the configuration of axiosInstance, please refer to the official website.

Note: Use the params of axiosInstance to receive the query condition, which is essentially an object in JSON format; the range type field needs to pass in the two values of start and end, and pass the judgment of if(str.includes(?)), otherwise the package function execution error

import { axiosInstance } from "./axios"

export function taskFind(query: object) {
  return axiosInstance({
    url:'/api/mongo/task/find',
    params:query, // Use params to receive the get request parameter object
    method: 'get'
  })
}

vue3>src>pinia>taskStore

It’s okay without pinia, the important thing is what it achieves

import { taskFind } from "@/api/task"
import { defineStore } from "pinia"
import { ElMessage } from "element-plus"
import 'element-plus/es/components/message/style/css'

export interface taskState {
  // array nested object, there are multiple objects, complex attributes
  taskData: [],
  taskNum: number,
  tableHeight: number, // table height: calculated according to the number of rows
}


export const taskStore = defineStore('task', {
  state: (): taskState => {
    return {
      taskData: [],
      taskNum: 0,
      tableHeight: 1200
    }
  },
  actions: {
    async getTask(query: object) {
      const resTask: any = await taskFind(query)
      if (resTask. status == 200) {
      const len = resTask.data.length
      // Calculate the table height based on the number of rows:
      if (len < 24) {
        // 40: table tr height
        this.tableHeight = (len + 2) * 40
      } else {
        this.tableHeight = 1600 // up to 1600px, much beyond the screen
      }
        // update data
        this.taskNum = resTask.data.length
        return this.taskData = resTask.data
      }
      ElMessage({
        message: resTask. message,
        type: 'warning'
      })
    }
  }
})

vue3>src>views>app>Task.vue

The data returned by the query is dynamically responded to and mounted to the el-table, and only the code related to data processing is shown here

import { taskStore } from '@/pinia/taskStore'

const useTaskStore = taskStore()

// Initialize the input value of the filter field, v-model is bound to the search box
let taskFieldValue: any = reactive({})
for (const key in taskField) {
  taskFieldValue[key] = ''
}

// Execute query search button: call pinia to search content from MongoDB according to conditions and return
let loading = ref(false) // data loading animation: mask and circle
const handleExc = async () => {
  loading. value = true
  // Search and return task content from MongoDB, render to table
  // console.log('taskFieldValue:', taskFieldValue);
  await useTaskStore. getTask(taskFieldValue)
  setTimeout(() => {
    loading.value = false // Usually loading is fast: only a little bit will be displayed
  }, 1000)
}


// load ongoing tasks by default!
onMounted(async () => {
  if (!useTaskStore. getTask) {
    location. reload()
  }
  await useTaskStore.getTask({ TState: "in progress" })
})

<!-- list: data display -->
<!-- table-layout:auto set the width according to the content of the first row? -->
<el-table :data="useTaskStore.taskData" style="width: 100%;" :height="useTaskStore.tableHeight" class="task-table"
  lazy @mousewheel="handleScroll" v-loading="loading" element-loading-text="Loading...">
  <el-table-column type="selection" width=".3rem" />
  <template v-for="(item, index) in taskField" :key="index">
    <el-table-column :prop="index" :label="item.label" :min-width="item.minWidth" :sortable="item.sortable"
      :fixed="item.fixed" :show-overflow-tooltip="item.showOverflowTooltip" :formatter="formatterDate"
      v-if="item.vShow" />
  </template>
</el-table>

end! The above display is only part of the code, not complete, for learning reference.

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Vue entry skill tree Node.js and npmNode installation and configuration