TypeORM github: https://github.com/typeorm/typeorm
這篇譯文是從TypeORM github上的使用說明上翻譯過來的,已經提交PR並merge到庫中了。
TypeORM是一個采用TypeScript編寫的用於Node.js的優秀ORM框架,支持使用TypeScript或Javascript(ES5, ES6, ES7)開發。
目標是保持支持最新的javascript特性來幫助開發各種用到數據庫的應用 - 不管是輕應用還是企業級的。
TypeORM可以做到:
- 根據Models自動創建數據庫Table
- 可以透明的insert/update/delete數據庫對象
- 映射數據庫table到javascript對象,映射table column到javascript對象屬性
- 提供表的一對一,多對一,一對多,多對多關系處理
- 還有更多 ...
不同於其他的JavaScript ORM,TypeORM使用的是數據映射模式,可以很輕松的創建出松耦合、可伸縮、可維護的應用。
TypeORM可以幫助開發者專註於業務邏輯,而不用過於擔心數據存儲的問題。
TypeORM參考了很多其他優秀ORM的實現, 比如 Hibernate, Doctrine 和 Entity Framework.
安裝
安裝TypeORM:
npm install typeorm --save
需要安裝依賴模塊
reflect-metadata
:npm install reflect-metadata --save
在應用裏全局引用一下:
- 比如在app.ts的入口處
require("reflect-metadata")
- 比如在app.ts的入口處
安裝數據庫驅動:
mysql 或 MariaDB
npm install mysql --save
Postgres
npm install pg --save
SQLite
npm install sqlite3 --save
Microsoft SQL Server
npm install mssql --save
Oracle (experimental)
npm install oracledb --save
可以根據你的數據庫選擇安裝上面的任意一個.
使用oracle驅動需要參考安裝說明:地址.
TypeScript配置
確保你的TypeScript編譯器的版本大於2.1,並且在tsconfig.json
開啟下面設置:
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
同時需要開啟編譯選項裏的lib
下的es6
或者從@typings
安裝es6-shim
Node.js 版本
TypeORM在Node.JS 4.0或以上版本上測試通過。
如果在應用啟動過程中出錯可以嘗試升級node.js到最新版本。
在瀏覽器中使用WebSQL (試用)
TypeORM可以在瀏覽器環境中工作,並且試驗性的支持WebSQL
如果在瀏覽器環境中使用TypeORM需要使用 npm i typeorm-browser
來替代 typeorm
.
更多相關可以參考這裏和這個例子.
快速開始
在TypeORM中,數據庫table都是從實體中創建。
所謂實體其實就是用裝飾器@Table
裝飾的一個model。
可以直接從數據庫中得到包含數據的實體對象,並且可以通過實體進行數據庫表的insert/update/remove。
來看看這個model entity/Photo.ts
:
export class Photo {
id: number;
name: string;
description: string;
fileName: string;
views: number;
}
創建實體
現在把Model變成實體:
import {Table} from "typeorm";
@Table()
export class Photo {
id: number;
name: string;
description: string;
fileName: string;
views: number;
isPublished: boolean;
}
添加table列
已經有了一個table,每個table都有column.
現在來添加列.
可以使用裝飾器@Column
來把model的屬性變成列:
import {Table, Column} from "typeorm";
@Table()
export class Photo {
@Column()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
fileName: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
創建一個主鍵列
很好, 現在ORM馬上就可以在數據庫中生成這個photo表,不過還漏了一個,每個table都必須要有主鍵列,所以要加上它。
可以用@PrimaryColumn
裝飾器來標記一個主鍵列。
import {Table, Column, PrimaryColumn} from "typeorm";
@Table()
export class Photo {
@PrimaryColumn()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
fileName: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
創建自增長/自生成/順序化的列
如果你想創建自增長/自生成/順序化的列,需要把column的type改成integer並且給主鍵列加上一個屬性{ generated: true }
import {Table, Column, PrimaryColumn} from "typeorm";
@Table()
export class Photo {
@PrimaryColumn("int", { generated: true })
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
fileName: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
使用 @PrimaryGeneratedColumn
裝飾器
現在photo表的id可能自動生成自動增長,不過還是有點麻煩,這個一個很常見的功能,所以有一個專門的裝飾器@PrimaryGeneratedColumn
來實現相同的功能。
import {Table, Column, PrimaryGeneratedColumn} from "typeorm";
@Table()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
description: string;
@Column()
fileName: string;
@Column()
views: number;
@Column()
isPublished: boolean;
}
自定義列的數據類型
接下來讓我們改一下列的數據類型。默認情況下,string類型的屬性會映射到數據庫裏varchar(255)的數據類型,number則會映射到類似於float/double這樣的數據類型(取決到是什麽數據庫)。
但是我們不想所有的列被限制在varchar或float之類,下面來改進:
import {Table, Column, PrimaryGeneratedColumn} from "typeorm";
@Table()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column({
length: 500
})
name: string;
@Column("text")
description: string;
@Column()
fileName: string;
@Column("int")
views: number;
@Column()
isPublished: boolean;
}
創建數據庫連接
現在實體已經有了,接下來創建app.ts
並配置數據庫連接:
import "reflect-metadata";
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
createConnection({
driver: {
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "admin",
database: "test"
},
entities: [
Photo
],
autoSchemaSync: true,
}).then(connection => {
// 這裏可以寫實體操作相關的代碼
}).catch(error => console.log(error));
在例子裏使用的是mysql,你也可以選擇其他數據庫,只需要簡單修改driver選項裏的數據庫的類型就可以了,比如:
mysql, mariadb, postgres, sqlite, mssql or oracle.
同樣可以修改host, port, username, password 以及database等設置.
把Photo實體加到數據連接的實體列表中,所有需要在這個連接下使用的實體都必須加到這個列表中。
autoSchemaSync
選項可以在應用啟動時確保你的實體和數據庫保持同步。
引用目錄下的所有實體
接下來我們可能會創建更多的實體並把它們一一加到配置當中。
不過這樣會比較麻煩,好在可以直接寫上實體的目錄,這樣這個目錄下的所有實體都可以在當前連接中被使用:
import {createConnection} from "typeorm";
createConnection({
driver: {
type: "mysql",
host: "localhost",
port: 3306,
username: "root",
password: "admin",
database: "test"
},
entities: [
__dirname + "/entity/*.js"
],
autoSchemaSync: true,
}).then(connection => {
// here you can start to work with your entities
}).catch(error => console.log(error));
啟動應用
現在可以啟動app.ts
,啟動後可以發現數據庫自動被初始化,並且Photo這個表也會創建出來。
+-------------+--------------+----------------------------+
| photo |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(500) | |
| description | text | |
| filename | varchar(255) | |
| views | int(11) | |
| isPublished | boolean | |
+-------------+--------------+----------------------------+
添加和插入photo
現在創建一個新的photo然後存到數據庫:
import {createConnection} from "typeorm";
createConnection(/*...*/).then(connection => {
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.views = 1;
photo.isPublished = true;
connection.entityManager
.persist(photo)
.then(photo => {
console.log("Photo has been saved");
});
}).catch(error => console.log(error));
使用async/await語法
現在利用TypeScript的async/await語法來實現同樣的功能:
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.views = 1;
photo.isPublished = true;
await connection.entityManager.persist(photo);
console.log("Photo has been saved");
}).catch(error => console.log(error));
使用EntityManager
剛剛我們創建了一個新的photo並且存進數據庫。使用EntityManager可以操作實體,現在用EntityManager
來把photo從數據庫中取出來。
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
/*...*/
let savedPhotos = await connection.entityManager.find(Photo);
console.log("All photos from the db: ", savedPhotos);
}).catch(error => console.log(error));
savedPhotos 會從數據庫中取到的是一個Photo對象的數組
使用Repositories
現在重構下代碼,使用Repository
來代替EntityManage。每個實體都有自己的repository,可以對這個實體進行任何操作。
如果要對實體做很多操作,Repositories會比EntityManager更加方便。
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg";
photo.views = 1;
photo.isPublished = true;
let photoRepository = connection.getRepository(Photo);
await photoRepository.persist(photo);
console.log("Photo has been saved");
let savedPhotos = await photoRepository.find();
console.log("All photos from the db: ", savedPhotos);
}).catch(error => console.log(error));
從數據庫中取photos
現在來嘗試用Repository做一些取數據方面的操作:
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
/*...*/
let allPhotos = await photoRepository.find();
console.log("All photos from the db: ", allPhotos);
let firstPhoto = await photoRepository.findOneById(1);
console.log("First photo from the db: ", firstPhoto);
let meAndBearsPhoto = await photoRepository.findOne({ name: "Me and Bears" });
console.log("Me and Bears photo from the db: ", meAndBearsPhoto);
let allViewedPhotos = await photoRepository.find({ views: 1 });
console.log("All viewed photos: ", allViewedPhotos);
let allPublishedPhotos = await photoRepository.find({ isPublished: true });
console.log("All published photos: ", allPublishedPhotos);
let [allPhotos, photosCount] = await photoRepository.findAndCount();
console.log("All photos: ", allPublishedPhotos);
console.log("Photos count: ", allPublishedPhotos);
}).catch(error => console.log(error));
更新photo
現在來從數據庫中取出一個photo,修改並更新到數據庫。
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
/*...*/
let photoToUpdate = await photoRepository.findOneById(1);
photoToUpdate.name = "Me, my friends and polar bears";
await photoRepository.persist(photoToUpdate);
}).catch(error => console.log(error));
這個id = 1
的photo在數據庫中就成功更新了.
刪除photo
再來,從數據庫中刪除我們的photo:
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
createConnection(/*...*/).then(async connection => {
/*...*/
let photoToRemove = await photoRepository.findOneById(1);
await photoRepository.remove(photoToRemove);
}).catch(error => console.log(error));
這個id = 1
的photo就在數據庫中被移除了。
一對一關系
來創建與另一個類的一對一關系。
新建PhotoMetadata.ts用來存photo的元信息。
import {Table, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn} from "typeorm";
import {Photo} from "./Photo";
@Table()
export class PhotoMetadata {
@PrimaryGeneratedColumn()
id: number;
@Column("int")
height: number;
@Column("int")
width: number;
@Column()
orientation: string;
@Column()
compressed: boolean;
@Column()
comment: string;
@OneToOne(type => Photo)
@JoinColumn()
photo: Photo;
}
這裏我們用到了一個新的裝飾器@OneToOne
,它可以用來在兩個實體之間創建一對一關系。
type => Photo
指示了我們想要連接的實體類名,這裏因為TypeScript語言的支持原因不能直接用類名。
當然也可以使用() => Photo
,但是type => Photo
顯得更有可讀性。
Type變量本身並不包含任何東西。
我們同樣使用了@JoinColumn
裝飾器,這個裝飾器可以指定一對一關系的擁有者。
關系可以是單向的或雙向的,但是只有一方是擁有者,加個這個裝飾器就表示關系是給這個表服務的。
現在運行app,會新創建一個table,這個table有一個連接photo的外鍵:
+-------------+--------------+----------------------------+
| photo `譯者註:應該是PhotoMetadata` |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| height | int(11) | |
| width | int(11) | |
| comment | varchar(255) | |
| compressed | boolean | |
| orientation | varchar(255) | |
| photo | int(11) | FOREIGN KEY |
+-------------+--------------+----------------------------+
存一個有一對一關系的對象
現在來創建一個photo,一個photo的元信息,並把它們已經連接起來。
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
import {PhotoMetadata} from "./entity/PhotoMetadata";
createConnection(/*...*/).then(async connection => {
// 創建一個photo
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg"
photo.isPublished = true;
// 創建一個photo的元信息
let metadata = http://www.cnblogs.com/brookshi/p/new PhotoMetadata();
metadata.height = 640;
metadata.width = 480;
metadata.compressed = true;
metadata.comment ="cybershoot";
metadata.orientation = "portait";
metadata.photo = photo; // 這裏把兩者連起來
// 獲取實體repositories
let photoRepository = connection.getRepository(Photo);
let metadataRepository = connection.getRepository(PhotoMetadata);
// 先來把photo存到數據庫
await photoRepository.persist(photo);
// photo存完了,再存下photo的元信息
await metadataRepository.persist(metadata);
// 搞定
console.log("metadata is saved, and relation between metadata and photo is created in the database too");
}).catch(error => console.log(error));
雙向關系
關系可以是單向的或是雙向的.
現在PhotoMetadata和Photo的關系是單向的,關系擁有者是PhotoMetadata,Photo並不知道PhotoMetadata,這樣如果要想從Photo裏得到PhotoMetadata的數據會比較麻煩。
現在來改變一下,把單向改成雙向:
import {Table, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn} from "typeorm";
import {Photo} from "./Photo";
@Table()
export class PhotoMetadata {
/* ... 其他列 */
@OneToOne(type => Photo, photo => photo.metadata)
@JoinColumn()
photo: Photo;
}
import {Table, Column, PrimaryGeneratedColumn, OneToOne} from "typeorm";
import {PhotoMetadata} from "./PhotoMetadata";
@Table()
export class Photo {
/* ... 其他列 */
@OneToOne(type => PhotoMetadata, photoMetadata =http://www.cnblogs.com/brookshi/p/> photoMetadata.photo)
metadata: PhotoMetadata;
}
photo => photo.metadata
是用來指定反向關系的字段名字,photo.metadata就指出了Photo裏的metadata字段名字。
當然也可以使用@OneToOne('metadata')
來達到同樣的目的,不過這種對於以後的代碼重構不友好。
按上面說的,@JoinColumn
只能在關系的一邊使用來使這邊做為關系的擁有者,關系擁有者在數據庫裏的表現就是擁有一個外鍵列。
取出關系對象的數據
現在來用一個查詢來取出photo以及它的元信息。
有兩種方式,一是用FindOptions
,另一個是使用QueryBuilder
。
先試下FindOptions
,通過指定FindOptions
接口作為參數來使用Repository.find
方法可以完成非常復雜的查詢。
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
import {PhotoMetadata} from "./entity/PhotoMetadata";
createConnection(/*...*/).then(async connection => {
/*...*/
let photoRepository = connection.getRepository(Photo);
let photos = await photoRepository.find({
alias: "photo",
innerJoinAndSelect: {
"metadata": "photo.metadata"
}
});
}).catch(error => console.log(error));
返回的photos是從數據庫裏取回的photo的數組,每個photo都包含它的元信息。
alias
是FindOptions的一個必需選項,這是你自己在select裏定義的別名,然後需要用在接下來的 where, order by, group by, join 以及其他表達式.
這裏還用到了innerJoinAndSelect
,表示內聯查詢photo.metadata的數據。
"photo.metadata"
裏"photo"是一個別名,"metadata"則是你想查詢的那個對象的屬性名。
"metadata"
: 是內聯返回數據的新的別名.
下面來嘗試第二種方式:QueryBuilder
來達到同樣的目的. 使用QueryBuilder
可以優雅完成復雜的查詢:
import {createConnection} from "typeorm";
import {Photo} from "./entity/Photo";
import {PhotoMetadata} from "./entity/PhotoMetadata";
createConnection(/*...*/).then(async connection => {
/*...*/
let photoRepository = connection.getRepository(Photo);
let photos = await photoRepository.createQueryBuilder("photo")
.innerJoinAndSelect("photo.metadata", "metadata")
.getMany();
}).catch(error => console.log(error));
使用 cascade 選項來自動保存關系著的對象
上面要保存關系對象需要一個一個來保存,略顯麻煩。
如果我們需要當關系對象中的一個被保存後,另一個也同樣被保存,則可以使用cascade
選項來做到。
稍微改下@OneToOne
裝飾:
export class Photo {
/// ... 其他列
@OneToOne(type => PhotoMetadata, metadata =http://www.cnblogs.com/brookshi/p/> metadata.photo, {
cascadeInsert: true,
cascadeUpdate: true,
cascadeRemove: true
})
metadata: PhotoMetadata;
}
- cascadeInsert - 如果表中沒有關系中的metadata,則自動insert,即我們不需要再手動insert一個新的photoMetadata對象。
- cascadeUpdate - 如果metadata有變化,則自動update。
- cascadeRemove - 如果把photo裏的metadata移除了,也就是為空,則會自動remove表中的這條metadata數據。
使用cascadeInsert就可以不需要像上面那邊先存photo再存metadata了。
現在我們來單單存photo對象,由於cascade的作用,metadata也會自動存上。
createConnection(options).then(async connection => {
// 創建photo對象
let photo = new Photo();
photo.name = "Me and Bears";
photo.description = "I am near polar bears";
photo.filename = "photo-with-bears.jpg"
photo.isPublished = true;
// 創建photo metadata 對象
let metadata = http://www.cnblogs.com/brookshi/p/new PhotoMetadata();
metadata.height = 640;
metadata.width = 480;
metadata.compressed = true;
metadata.comment ="cybershoot";
metadata.orientation = "portait";
photo.metadata = http://www.cnblogs.com/brookshi/p/metadata; // 連接起來
// 得到repository
let photoRepository = connection.getRepository(Photo);
// 存photo
await photoRepository.persist(photo);
// photo metadata也自動存上了
console.log("Photo is saved, photo metadata is saved too.")
}).catch(error => console.log(error));
多對一/一對多關系
接下來顯示多對一/一對多關系。
假設一個photo會有一個author,並且每個author可以有很多photo。
先創建Author實體:
import {Table, Column, PrimaryGeneratedColumn, OneToMany, JoinColumn} from "typeorm";
import {Photo} from "./Photo";
@Table()
export class Author {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(type => Photo, photo => photo.author) // 備註:下面會為Photo創建author屬性
photos: Photo[];
}
Author包含一個反向的關系,OneToMany
總是反向的,並且總是與ManyToOne
成對出現。
現在來為Photo加上關系擁有者。
import {Table, Column, PrimaryGeneratedColumn, ManyToOne} from "typeorm";
import {PhotoMetadata} from "./PhotoMetadata";
import {Author} from "./Author";
@Table()
export class Photo {
/* ... 其他列 */
@ManyToOne(type => Author, author => author.photos)
author: Author;
}
在ManyToOne/OneToMany
關系中,擁有者一邊總是ManyToOne
。譯者註:擁有外鍵者即關系擁有者
也就是ManyToOne
的那個字段存的是另一個對象的id。譯者註:也就是上面的author雖然屬性是Author,但在數據庫中類型是Author id的類型,存的也是id
執行上面的代碼將會自動創建author表,如下:
+-------------+--------------+----------------------------+
| author |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
+-------------+--------------+----------------------------+
因為photo表已經存在,所以不是增加而是修改photo表 - 添加一個新外鍵列author:
+-------------+--------------+----------------------------+
| photo |
+-------------+--------------+----------------------------+
| id | int(11) | PRIMARY KEY AUTO_INCREMENT |
| name | varchar(255) | |
| description | varchar(255) | |
| filename | varchar(255) | |
| isPublished | boolean | |
| author | int(11) | FOREIGN KEY |
+-------------+--------------+----------------------------+
多對多關系
假設photo可以存在多個相冊中,並且相冊裏可以包含多個photo。
先創建一個Album
類
import {Table, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable} from "typeorm";
@Table()
export class Album {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@ManyToMany(type => Photo, photo => photo.albums, { // 備註: 會在下面的Photo類裏添加"albums"屬性
cascadeInsert: true, // 在添加Album時,會自動添加相冊裏的Photo
cascadeUpdate: true, // 在更新Album時,會自動更新相冊裏的Photo
cascadeRemove: true // 在移除Album時,會自動移除相冊裏的Photo
})
@JoinTable()
photos: Photo[] = []; // 初始化個Photo數組
}
@JoinTable
多對多關系擁有者必須指定的。
接著給Photo
實體加個反向關系:
export class Photo {
/// ... 其他列
@ManyToMany(type => Album, album => album.photos, {
cascadeInsert: true, // 在添加Album時,會自動添加相冊裏的Photo
cascadeUpdate: true, // 在更新Album時,會自動更新相冊裏的Photo
cascadeRemove: true // 在移除Album時,會自動移除相冊裏的Photo
})
albums: Album[] = []; // 初始化個Album數組
}
執行上面的代碼後會自動創建一個叫 album_photos_photo_albums的聯接表:
+-------------+--------------+----------------------------+
| album_photos_photo_albums |
+-------------+--------------+----------------------------+
| album_id_1 | int(11) | PRIMARY KEY FOREIGN KEY |
| photo_id_2 | int(11) | PRIMARY KEY FOREIGN KEY |
+-------------+--------------+----------------------------+
記得把Album
實體加到ConnectionOptions中:
const options: CreateConnectionOptions = {
// ... 其他配置
entities: [Photo, PhotoMetadata, Author, Album]
};
現在來往數據庫裏插入albums和photos
let connection = await createConnection(options);
// 創建兩個albums
let album1 = new Album();
album1.name = "Bears";
let album2 = new Album();
album2.name = "Me";
// 創建兩個photos
let photo1 = new Photo();
photo1.name = "Me and Bears";
photo1.description = "I am near polar bears";
photo1.filename = "photo-with-bears.jpg";
photo1.albums.push(album1);
let photo2 = new Photo();
photo2.name = "Me and Bears";
photo2.description = "I am near polar bears";
photo2.filename = "photo-with-bears.jpg";
photo2.albums.push(album2);
// 獲取Photo的repository
let photoRepository = connection.getRepository(Photo);
// 依次存儲photos,由於cascade,albums也同樣會自動存起來
await photoRepository.persist(photo1);
await photoRepository.persist(photo2);
console.log("Both photos have been saved");
使用QueryBuilder
可以利用QueryBuilder來構建一個非常復雜的查詢,例如:
let photoRepository = connection.getRepository(Photo);
let photos = await photoRepository
.createQueryBuilder("photo") // 別名,必填項,用來指定本次查詢
.innerJoinAndSelect("photo.metadata", "metadata")
.leftJoinAndSelect("photo.albums", "albums")
.where("photo.isPublished=true")
.andWhere("(photo.name=:photoName OR photo.name=:bearName)")
.orderBy("photo.id", "DESC")
.setFirstResult(5)
.setMaxResults(10)
.setParameters({ photoName: "My", bearName: "Mishka" })
.getMany();
這個查詢會查找已經published的,並且name是"My"或"Mishka",
得到的結果會從第5個開始(分頁偏移決定的),
並且只會得到10個結果(分頁每頁個數決定的),
所得結果是以id的倒序排序的,
Photo的albums是左聯接,photo的metadata是內聯接。
更多關於QueryBuilder可以查看這裏.
Tags: javascript require insert update 數據庫
文章來源: