mongoose/mongodb 常用用法

129 阅读3分钟

创建连接

单个连接

mongoose.connect('mongodb://127.0.0.1:27017/myapp')
mongoose.connect('mongodb://username:password@host:port/database?options...')

多个连接

const conn = mongoose.createConnection('mongodb://127.0.0.1:27017/myapp')
conn.asPromise() // 连接成功

建立schema

嵌套对象定义

interface Inventory {
  item: string
  qty: number
  size?: { h: number; w?: number; uom?: string }
  status: string
}

const inventorySchema = new mongoose.Schema<Inventory>(
  {
    item: { type: String, required: true },
    qty: { type: Number, required: true },
    size: {
      h: { type: Number, required: true }, 
      w: Number, 
      uom: String
    },
    status: { type: String, required: true },
  },
  { versionKey: false },
)

注意:当字段名为type时,必需再嵌套一层type指定其类型,否则type字段会被识别成类型

隐患:当插入文档时,如果不提供size字段,会出现以下错误:

Error: Inventory validation failed: size.h: Path size.h is required.

理论上size是非必需字段才对呀

嵌套对象定义(嵌套对象字段不必需,但对象里的某个属性必需)

interface Inventory {
  item: string
  qty: number
  size?: { h: number; w?: number; uom?: string }
  status: string
}

const inventorySchema = new mongoose.Schema<Inventory>(
  {
    item: { type: String, required: true },
    qty: { type: Number, required: true },
    size: {
      type: { h: { type: Number, required: true }, w: Number, uom: String },
      _id: false
    },
    status: { type: String, required: true },
  },
  { versionKey: false },
)

为什么需要_id: false?

当使用type定义嵌套对象类型时,等同于嵌入了一个子文档(定义方式如下),子文档和文档都必须包含_id属性,如果你不需要_id,需要手动指定为false

子文档定义

interface InventorySize {
  h: number
  w: number
  uom: string
}

interface Inventory {
  item: string
  qty: number
  size: InventorySize
  status: string
}

const inventorySizeSchema = new mongoose.Schema<InventorySize>(
  {
    h: { type: Number, required: true },
    w: Number,
    uom: String,
  },
  { _id: false },
)

const inventorySchema = new mongoose.Schema<Inventory>(
  {
    item: { type: String, required: true },
    qty: { type: Number, required: true },
    size: inventorySizeSchema,
    status: { type: String, required: true },
  },
  { versionKey: false },
)

建立model

const inventoryModel = mongoose.model('Inventory', inventorySchema, 'inventory')
const inventoryModel = conn.model('Inventory', inventorySchema, 'inventory')

查询

对嵌入/嵌套文档的查询

await inventoryModel.insertMany([
  {
    item: 'journal',
    qty: 25,
    size: { h: 14, w: 21, uom: 'cm' },
    status: 'A'
  },
  {
    item: 'notebook',
    qty: 50,
    size: { h: 8.5, w: 11, uom: 'in' },
    status: 'A'
  },
  {
    item: 'paper',
    qty: 100,
    size: { h: 8.5, w: 11, uom: 'in' },
    status: 'D'
  },
  {
    item: 'planner',
    qty: 75,
    size: { h: 22.85, w: 30, uom: 'cm' },
    status: 'D'
  },
  {
    item: 'postcard',
    qty: 45,
    size: { h: 10, w: 15.25, uom: 'cm' },
    status: 'A'
  }
]);

以下示例使用该 inventory 集合

使用点表示法 查询嵌套字段

await inventoryModel.find({ 'size.uom': 'in' })

选择嵌套在 size 字段中的字段 uom 等于 "in" 的所有文档

await inventoryModel.find({ 'size.h': { $lt: 15 } })

选择嵌套在 size 字段中的字段 h 小于 15 的所有文档

匹配嵌入/嵌套的文档

await inventoryModel.find({ size: { h: 14, w: 21, uom: 'cm' } })

选择字段 size等于文档 { h: 14, w: 21, uom: "cm" } 的所有文档

警告:MongoDB不建议在嵌入式文档上进行相等匹配,因为操作需要指定 <value> 文档的精确匹配,包括字段顺序。

查询数组

await inventoryModel.insertMany([
  {
    item: 'journal',
    qty: 25,
    tags: ['blank', 'red'],
    dim_cm: [14, 21]
  },
  {
    item: 'notebook',
    qty: 50,
    tags: ['red', 'blank'],
    dim_cm: [14, 21]
  },
  {
    item: 'paper',
    qty: 100,
    tags: ['red', 'blank', 'plain'],
    dim_cm: [14, 21]
  },
  {
    item: 'planner',
    qty: 75,
    tags: ['blank', 'red'],
    dim_cm: [22.85, 30]
  },
  {
    item: 'postcard',
    qty: 45,
    tags: ['blue'],
    dim_cm: [10, 15.25]
  }
]);

以下示例使用该 inventory 集合

匹配数组

await inventoryModel.find({ tags: ['red', 'blank'] })

查询字段tags值为数组,且 恰好 包含redblank两个元素(包括元素的顺序)的所有文档

await inventoryModel.find({ tags: { $all: ['red', 'blank'] } })

查询字段tags值为数组,且包含redblank两个元素(不考虑元素的顺序或其他元素)的所有文档

在数组中查询元素

await inventoryModel.find({ tags: 'red' })

查询字段tags为数组,且包含字符串red作为其中一个元素的所有文档

为数组元素指定多个条件

await return inventoryModel.find({ dim_cm: { $gt: 15, $lt: 20 } })

查询文档,其中 dim_cm 数组包含以某种方式组合满足查询条件的元素;例如,一个元素可以满足大于15条件,另一个元素可以满足小于20条件,或者单个元素可以同时满足

(个人感觉基本用不到。。。)

await return inventoryModel.find({ dim_cm: { $elemMatch: { $gt: 22, $lt: 30 } } })

查询dim_cm数组中至少有一个元素大于22且小于30的所有文档

await return inventoryModel.find({ 'dim_cm.1': { $gt: 25 } })

查询dim_cm数组中第二个元素大于25的所有文档

await return inventoryModel.find({ tags: { $size: 3 } })

查询tags数组中包含3个元素的所有文档

查询嵌入文档的数组

await inventoryModel.insertMany([
  {
    item: 'journal',
    instock: [
      { warehouse: 'A', qty: 5 },
      { warehouse: 'C', qty: 15 }
    ]
  },
  {
    item: 'notebook',
    instock: [{ warehouse: 'C', qty: 5 }]
  },
  {
    item: 'paper',
    instock: [
      { warehouse: 'A', qty: 60 },
      { warehouse: 'B', qty: 15 }
    ]
  },
  {
    item: 'planner',
    instock: [
      { warehouse: 'A', qty: 40 },
      { warehouse: 'B', qty: 5 }
    ]
  },
  {
    item: 'postcard',
    instock: [
      { warehouse: 'B', qty: 15 },
      { warehouse: 'C', qty: 35 }
    ]
  }
]);

匹配嵌套在数组中的文档

await inventoryModel.find({ instock: { warehouse: 'A', qty: 5 } })

查询instock数组中元素与指定文档匹配的所有文档(整个嵌入/嵌套文档上的相等匹配要求指定文档的完全匹配,包括字段顺序)

在文档数组中的字段上指定查询条件

await inventoryModel.find({ 'instock.qty': { $lte: 20 } })

查询instock数组中至少有一个嵌入文档包含qty字段,且值小于或等于20的所有文档

await inventoryModel.find({ 'instock.0.qty': { $lte: 20 } })

查询instock数组中的第一个元素包含qty字段,且值小于或等于20的所有文档

为文档数组指定多个条件

await inventoryModel.find({ instock: { $elemMatch: { qty: 5, warehouse: 'A' } } })

查询instock数组中至少有一个嵌入文档,包含qty字段等于5warehouse字段等于A的所有文档

await inventoryModel.find({ 'instock.qty': { $gt: 10, $lte: 20 } })

查询匹配任何嵌套在instock数组中的文档的qty字段大于10,且数组中任何文档(但不一定是相同的嵌入文档)的qty字段小于或等于20的所有文档

(跟前面为数组元素指定多个条件类似。。。)