import { Collection, CreateIndexesOptions, Db, IndexDescription, IndexSpecification, MongoClient, MongoClientOptions, ObjectId, OptionalId } from 'mongodb'; import {CollectionActionLog, actionLogType} from './module/collection_actionLog'; import {CollectionEvent, eventType} from './module/collection_event'; import {CollectionPlayerInfo, playerInfoType} from './module/collection_palyerInfo'; import {CollectionRecord, recordType} from './module/collection_record'; import {MongodbCollections} from './module/mongodb'; import {HuoDongFun} from './public/huodongfun'; import {zbsGroup} from './api_s2c/hbzb/zbs/fun'; import {clusterRunOnce} from './clusterUtils'; import { PublicShared } from './shared/public/public'; const indexs: Partial<{ [k in keyof MongodbCollections]: IndexDescription[] }> = { item: [ { key: {uid: 1, itemId: 1}, unique: true }, { key: {uid: 1} } ], user: [ { key: {bindUid: 1, sid: 1}, unique: true, }, { key: {name: 1}, unique: true, }, { key: {uid: 1}, unique: true, }, { key: {mapId: 1}, } ], hero: [ { key: {uid: 1, _id: 1}, unique: true }, { key: {uid: 1} } ], equip: [ { key: {uid: 1, _id: 1}, unique: true }, { key: {uid: 1} } ], shiwu: [ { key: {uid: 1, _id: 1}, unique: true }, { key: {uid: 1} } ], email: [ { key: {uid: 1, _id: 1}, unique: true }, { key: {ttl: 1}, expireAfterSeconds: 15 * 24 * 3600 }, { key: {uid: 1} } ], xstask: [ { key: {uid: 1, _id: 1}, unique: true }, { key: {uid: 1} } ], playerInfo: [ { key: {uid: 1, type: 1}, unique: true }, { key: {uid: 1} } ], pata: [ { key: {uid: 1, sid: 1}, unique: true }, { key: {uid: 1} } ], gbtx: [ { key: {uid: 1}, unique: true } ], tanxian: [ { key: {uid: 1}, unique: true } ], cardlog: [ { key: {uid: 1, cardnum: 1}, unique: true } ], dxlt: [ { key: {uid: 1}, unique: true } ], jjc: [ { key: {uid: 1}, unique: true } ], playattr: [ { key: {uid: 1, ctype: 1}, unique: true } ], gonghui: [ { key: {name: 1}, unique: true } ], gonghuiUser: [ { key: {uid: 1}, unique: true } ], gonghuiFb: [ { key: {ghId: 1, fbId: 1}, unique: true } ], task: [ { key: {uid: 1, taskid: 1}, unique: true }, { key: {uid: 1} }, { key: {stype: 1} }, { key: {pval: 1} }, { key: {nval: 1} } ], actionLog: [ { key: {uid: 1, type: 1}, unique: true } ], syncBtns: [ { key: {uid: 1}, unique: true } ], payLog: [ { key: {uid: 1}, unique: true } ], event: [ { key: {uid: 1, type: 1}, unique: true }, { key: {uid: 1} } ], friend: [ { key: {uid: 1}, unique: true } ], chat: [ { key: {type: 1}, unique: true } ], chatLog: [ { key: {uid: 1} }, { key: {type: 1} } ], slzdGh: [ { key: {ghid: 1}, unique: true } ], slzdUser: [ { key: {uid: 1}, unique: true } ], ganhai: [ { key: {uid: 1}, unique: true } ], dayPay: [ { key: {uid: 1, time: 1}, unique: true }, { key: {uid: 1} } ], rankList: [ { key: {type: 1, idKey: 1}, unique: true } ], wanted: [ { key: {uid: 1}, unique: true } ], peijian: [ { key: {uid: 1, _id: 1}, unique: true } ], mingdao: [ { key: {uid: 1}, unique: true } ], wjjl: [ { key: {uid: 1}, unique: true } ], zhanling: [ { key: {uid: 1, type: 1}, unique: true }, { key: {uid: 1} } ], hdinfo: [ { key: {hdid: 1}, unique: true }, { key: {htype: 1} }, { key: {ttype: 1} }, { key: {stime: 1} }, { key: {etime: 1} } ], giftLog: [ { key: {popup_id: 1}, unique: true }, { key: {game_user_id: 1} } ], loginLog: [ { key: {uid: 1, _id: 1}, unique: true }, { key: {uid: 1} } ], payLogNew: [ { key: {uid: 1, key: 1} }, { key: {uid: 1} } ], kuangdong: [ { key: {uid: 1} } ], apiCount: [ { key: {api: 1}, unique: true } ], weixiuchang: [ { key: {uid: 1}, unique: true } ], player_behavior: [ { key: {uid: 1, type: 1}, unique: true }, { key: {uid: 1} } ], rmbuse: [ { key: {uid: 1} } ], fightLog: [ { key: {uid: 1, type: 1} }, { key: {uid: 1} }, { key: {ttl: 1}, expireAfterSeconds: 7 * 24 * 3600 } ], shop: [ { key: {uid: 1, shopId: 1}, unique: true }, { key: {uid: 1} } ] }; const crossIndexs: Partial<{ [k in keyof MongodbCollections]: IndexDescription[] }> = { email: [ { key: {sid: 1} }, { key: {uid: 1} } ], fightLog: [ { key: {uid: 1, type: 1} }, { key: {uid: 1} }, { key: {ttl: 1}, expireAfterSeconds: 7 * 24 * 3600 } ], hbzb_user_cross: [ { key: {uid: 1}, unique: true }, { key: {jifen: 1} }, { key: {rank: 1} }, { key: {zbsgroup: 1} } ], hbzb_user_zbs: [ { key: {uid: 1}, unique: true } ], kbzzApplyUser: [ { key: {uid: 1}, unique: true } ], kbzzGroupUser: [ { key: {uid: 1}, unique: true } ], clslCrossUser: [ { key: {uid: 1}, unique: true } ], rankList: [ { key: {type: 1, idKey: 1}, unique: true }, { key: {valArr: -1} }, ], wzry_fight: [ { key: {jifen: 1} }, { key: {uid: 1} }, { key: {zkey: 1} }, ], wzry_user_cross: [ { key: {jifen: 1} }, { key: {uid: 1} }, { key: {zkey: 1} }, ] }; export async function initMongoDB() { //mongodb连接数说明:https://blog.csdn.net/for_cxc/article/details/116859714 //可结合查看:node_modules\mongodb\lib\connection_string.js //maxPoolSize默认值:100 let option:MongoClientOptions; //跨服只有1个,直接采用默认配置就行 if(G.argv.serverType != 'cross'){ if(PublicShared.getOpenServerDay() > 3){ option = { maxPoolSize: 10 } } } console.log('connect mongodb ......'); let client = await MongoClient.connect(G.argv.serverType == 'cross' ? G.config.crossMongodbUrl : G.config.mongodbUrl, option); G.mongodb = new _mongodb(client.db(G.config.dbName || '')); console.log('connect mongodb succ'); if (G.argv.serverType != 'cross') { console.log('connect crossmongodb ......'); //本服里,维持住跟跨服数据库的链接 let crossClient = await MongoClient.connect(G.config.crossMongodbUrl,{ maxPoolSize:10 }); G.crossmongodb = new _mongodb(crossClient.db(G.config.corssDBName || "")); console.log('connect crossmongodb succ'); } clusterRunOnce(() => { //只在集群的一个进程里进行即可 setDbIndexes(); }); } /**根据配置,设置mongodb的索引 */ export async function setDbIndexes() { let _indexs = G.argv.serverType == 'cross' ? crossIndexs : indexs; for (let coll in _indexs) { for (let i = 0; i < _indexs[coll].length; i++) { let index = _indexs[coll][i]; let option = {} as CreateIndexesOptions; if (index.unique != null) { option.unique = index.unique; } if (index.expireAfterSeconds != null) { option.expireAfterSeconds = index.expireAfterSeconds; } try { await G.mongodb.collection(coll as keyof MongodbCollections).createIndex( index.key, option ); console.log('创建索引成功', coll, index); } catch (error) { if (error.codeName == 'IndexKeySpecsConflict') { //当相同索引存在,但是配置(如:unique expireAfterSeconds)不同时,会收到这个报错 //此时会把原来的索引删除后重建 console.log('创建索引失败,和已有的索引冲突,尝试删除后重建'); await G.mongodb.collection(coll as keyof MongodbCollections).dropIndex(index.key); //再试一次,不行只能抛出错误了 try { await G.mongodb.collection(coll as keyof MongodbCollections).createIndex( index.key, option ); console.log('创建索引成功', coll, index); } catch (error) { console.log('创建索引失败==>', coll, index, error.message); } } else { console.log('创建索引失败=>', coll, index, error.message); } } } } } export class _mongodb { constructor(private db: Db) { } /** * mongodb仿sql查询 * @param field 需要获取的字段,空数组表示所有字段,如:["uid","lv"] * @param from 从哪个表查询 * @param where 查询条件,如:{"uid":"ciniao"} * @param order 排序条件,如:{"field":1} * @param limit 指定行数:10 * @returns */ fmtOption(field?: string[], order?: any, limit?: number) { let option = {}; if (field?.length > 0) { option['projection'] = {}; for (let i = 0; i < field.length; i++) { option['projection'][field[i]] = 1; } } if (order != null) { option['sort'] = order; } if (limit != null) { option['limit'] = limit; } return option; } async find(from: string, where: any, field?: string[], order?: any, limit?: number) { let option = this.fmtOption(field, order, limit); return this.db.collection(from).find(where, option).toArray(); } async findOne(from: string, where: any, field?: string[], order?: any, limit?: number) { let option = this.fmtOption(field, order, limit); return this.db.collection(from).findOne(where, option); } collection(collection: T): Collection>; collection(collection: 'playerInfo', type: T): Collection>>; collection(collection: string) { return this.db.collection(collection); } cActionLog(type: T): Collection>> { return this.db.collection('actionLog'); } cEvent(type: T): Collection>> { return this.db.collection('event'); } cPlayerInfo(type: T): Collection>> { return this.db.collection('playerInfo'); } cRecord(type: T): Collection>> { return this.db.collection('record'); } /**_id转化 */ conversionId(_id: string): ObjectId; conversionId(_id: ObjectId): string; conversionId(_id: string | ObjectId) { if (!_id) return null; if (_id instanceof ObjectId) return _id.toHexString(); else return new ObjectId(_id); } /**_id数据转化 */ conversionIdObj(obj: T): Omit & { _id: ObjectId; }; conversionIdObj(obj: T): Omit & { _id: string; }; conversionIdObj(obj: { _id: string; } | { _id: ObjectId; }) { if (!obj) return null; let {_id, ...ops} = obj; if (!_id) return ops; return { _id: this.conversionId(_id as any), ...ops } as any; } createTreeObj(...args: { key: string, val: any; }[]); createTreeObj(...args: { key: string, k: string, val: any; }[]); createTreeObj(...args: { key: string, k: string, val: any; }[]) { let obj = {}; args.forEach(v => { if (Object.keys(v).length == 2) { obj[v.key] = v.val; } else { obj[`${v.key}.${v.k}`] = v.val; } }); return obj; } // 增加查询索引(以达到检查数据库是否可用的目的) indexInformation(name) { return this.db.indexInformation(name) } }