package api import ( "mats/db/model" "mats/db/repo" "time" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" "infish.cn/comm" ) func UploadAsset2(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf) (interface{}, error) { switch dbConf.AssetConf.Type { case model.AssetTypeMesh: body := &model.AssetPackage{} c.ShouldBindJSON(body) body.Source.ViewMode = "prod" if apictx.User != nil { body.UserId, _ = primitive.ObjectIDFromHex(apictx.User.ID) } return UploadAssetPackage(apictx, dbConf, body) case model.AssetTypePackage: body := &model.AssetPackage{} c.ShouldBindJSON(body) body.Source.ViewMode = "scene" if apictx.User != nil { body.UserId, _ = primitive.ObjectIDFromHex(apictx.User.ID) } return UploadAssetPackage(apictx, dbConf, body) case model.AssetTypeEnv3d: body := &model.AssetEnv3dHdr{} c.ShouldBindJSON(body) if apictx.User != nil { body.UserId, _ = primitive.ObjectIDFromHex(apictx.User.ID) } return UploadEnv3d(apictx, dbConf, body) case model.AssetTypeMaterial: body := &comm.AssetMat{} c.ShouldBindJSON(body) if apictx.User != nil { body.UserId, _ = primitive.ObjectIDFromHex(apictx.User.ID) } return UploadMaterial(apictx, dbConf, body) case model.AssetTypeMaterialGroup: body := &comm.AssetMatGroup{} err := c.ShouldBindJSON(body) if err != nil { return nil, err } if apictx.User != nil { body.UserId, _ = primitive.ObjectIDFromHex(apictx.User.ID) } return UploadMaterialGroup(apictx, dbConf, body) case model.AssetTypeImage: body := &model.AssetImage{} c.ShouldBindJSON(body) if apictx.User != nil { body.UserId, _ = primitive.ObjectIDFromHex(apictx.User.ID) } return UploadImage(apictx, dbConf, body) } return nil, NewError("不支持的上传类型") } func PublicAssetList(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf) (interface{}, error) { page, size, query, fields := UtilQueryPageSize2(c) collectionName := dbConf.AssetConf.Collection err := ParseCategories(query, apictx, dbConf) if err != nil { return nil, err } project := []string{"name"} if dbConf.AssetConf.Type == model.AssetTypeMesh { project = []string{"name", "assetState", "source"} } if len(fields) > 0 { project = fields } out, err := repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ Db: dbConf.Db.Name, CollectName: collectionName, Page: page, Size: size, Query: query, Project: project, Sort: bson.M{"createTime": -1}, }) if err != nil { return nil, err } for _, item := range out.List { item["defineId"] = dbConf.AssetConf.Id } return out, nil } func AssetList(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf) (interface{}, error) { page, size, query, fields := UtilQueryPageSize2(c) collectionName := dbConf.AssetConf.Collection if query["userId"] != nil && len(query["userId"].(string)) > 0 { query["userId"], _ = primitive.ObjectIDFromHex(apictx.User.ID) } if query["ownerId"] != nil && len(query["ownerId"].(string)) > 0 { query["ownerId"], _ = primitive.ObjectIDFromHex(query["ownerId"].(string)) } err := ParseCategories(query, apictx, dbConf) if err != nil { return nil, err } project := []string{"name"} if dbConf.AssetConf.Type == model.AssetTypeMesh { project = []string{"name", "assetState", "source"} } if len(fields) > 0 { project = fields } out, err := repo.RepoPageSearch(apictx.CreateRepoCtx(), &repo.PageSearchOptions{ Db: dbConf.Db.Name, CollectName: collectionName, Page: page, Size: size, Query: query, Project: project, Sort: bson.M{"createTime": -1}, }) if err != nil { return nil, err } for _, item := range out.List { item["defineId"] = dbConf.AssetConf.Id } return out, nil } func AssetDelete(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf, id string) (interface{}, error) { return repo.RepoDeleteDbDoc(apictx.CreateRepoCtx(), dbConf.Db.Name, dbConf.AssetConf.Collection, id) } func AssetCopy(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf, id string, toDbConf *model.AssetDbConf, ownerId string, ownerType string, assetType string) (interface{}, error) { collectionName := dbConf.AssetConf.Collection var body model.IAsset switch dbConf.AssetConf.Type { case model.AssetTypeMesh: body = &model.AssetPackage{} case model.AssetTypeEnv3d: body = &model.AssetEnv3dHdr{} case model.AssetTypeMaterial: body = &comm.AssetMat{} case model.AssetTypeMaterialGroup: body = &comm.AssetMatGroup{} case model.AssetTypeImage: body = &model.AssetImage{} case model.AssetTypePackage: body = &model.AssetPackage{} } if body == nil { return nil, NewError("不支持的拷贝类型") } ok, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ Db: dbConf.Db.Name, CollectName: collectionName, Query: repo.Map{"_id": id}, }, body) if !ok { return nil, NewError("资产已删除!") } if err != nil { return nil, err } body.SetIdEmpty() body.ResetCreateTime() body.SetOwner(ownerId, ownerType) if len(assetType) > 0 { body.SetAssetType(assetType) } return repo.RepoDbAddDoc(apictx.CreateRepoCtx(), toDbConf.Db.Name, toDbConf.AssetConf.Collection, body) } func AssetCopy2My(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf, id string, toDbConf *model.AssetDbConf, ownerId string, ownerType string, assetType string) (interface{}, error) { collectionName := dbConf.AssetConf.Collection var body model.IAsset switch dbConf.AssetConf.Type { case model.AssetTypeMesh: body = &model.AssetPackage{} case model.AssetTypeEnv3d: body = &model.AssetEnv3dHdr{} case model.AssetTypeMaterial: body = &comm.AssetMat{} case model.AssetTypeMaterialGroup: body = &comm.AssetMatGroup{} case model.AssetTypeImage: body = &model.AssetImage{} case model.AssetTypePackage: body = &model.AssetPackage{} } if body == nil { return nil, NewError("不支持的拷贝类型") } ok, err := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ Db: dbConf.Db.Name, CollectName: collectionName, Query: repo.Map{"_id": id}, }, body) if !ok { return nil, NewError("资产已删除!") } if err != nil { return nil, err } body.SetIdEmpty() body.ResetCreateTime() body.SetOwner(ownerId, ownerType) if len(assetType) > 0 { body.SetAssetType(assetType) } //todo fixme 设置用户自己的信息 // info, err := bus.NatsCenter.GetUserInfo(apictx.User.ID) // if err != nil { // return nil, err // } //body.SetUserInfo(apictx.User.ID, &comm.AssetUserInfo{Name: info.Name, Thumbnail: &comm.OssType{Url: info.Avatar, Size: 0}}) body.SetUserInfo(apictx.User.ID, nil) return repo.RepoDbAddDoc(apictx.CreateRepoCtx(), toDbConf.Db.Name, toDbConf.AssetConf.Collection, body) } func AssetDetail(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf, id string) (interface{}, error) { _, _, _, fields := UtilQueryPageSize2(c) collectionName := dbConf.AssetConf.Collection project := []string{"name", "thumbnail", "createTime", "assetType", "cusNum", "state", "categories", "cusCategories", "source", "assetState", "userData"} if len(fields) > 0 { project = fields } ok, body := repo.RepoSeachDocMap(apictx.CreateRepoCtx(), &repo.DocSearchOptions{ Db: dbConf.Db.Name, CollectName: collectionName, Query: repo.Map{"_id": id}, Project: project, }) if !ok { return nil, NewError("资产不存在!") } return body, nil } func AssetUpdateComm(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf) (interface{}, error) { switch dbConf.AssetConf.Type { case model.AssetTypeMesh: body := &model.AssetPackage{} c.ShouldBindJSON(body) body.Source.ViewMode = "prod" return UpdateAssetPackageComm(apictx, dbConf, body) case model.AssetTypeEnv3d: body := &model.AssetEnv3dHdr{} c.ShouldBindJSON(body) return UpdateHdrComm(apictx, dbConf, body) case model.AssetTypeMaterial: body := &comm.AssetMat{} c.ShouldBindJSON(body) return UpdateMaterialComm(apictx, dbConf, body) case model.AssetTypeMaterialGroup: body := &comm.AssetMatGroup{} c.ShouldBindJSON(body) return UpdateMaterialGroup(apictx, dbConf, body) case model.AssetTypeImage: body := &model.AssetImage{} c.ShouldBindJSON(body) return UpdateImageComm(apictx, dbConf, body) case model.AssetTypePackage: body := &model.AssetPackage{} c.ShouldBindJSON(body) if body.Source != nil { body.Source.ViewMode = "scene" } return UpdateAssetPackageComm(apictx, dbConf, body) } return nil, NewError("不支持的类型") } func AssetUpdateSource(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf) (interface{}, error) { switch dbConf.AssetConf.Type { case model.AssetTypeMesh: body := &model.AssetPackage{} c.ShouldBindJSON(body) return UpdateAssetPackageSource(apictx, dbConf, body) case model.AssetTypePackage: body := &model.AssetPackage{} c.ShouldBindJSON(body) return UpdateAssetPackageSource(apictx, dbConf, body) case model.AssetTypeEnv3d: body := &model.AssetEnv3dHdr{} c.ShouldBindJSON(body) return UpdateHdrSource(apictx, dbConf, body) case model.AssetTypeMaterial: body := &comm.AssetMat{} c.ShouldBindJSON(body) return UpdateMaterialComm(apictx, dbConf, body) case model.AssetTypeMaterialGroup: body := &comm.AssetMatGroup{} c.ShouldBindJSON(body) return UpdateMaterialGroup(apictx, dbConf, body) case model.AssetTypeImage: body := &model.AssetImage{} c.ShouldBindJSON(body) return UpdateImageSource(apictx, dbConf, body) } return nil, NewError("不支持的类型") } func InsertAsset(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf) (interface{}, error) { var asset interface{} = nil switch dbConf.AssetConf.Type { case model.AssetTypeMesh: case model.AssetTypePackage: body := &model.AssetPackage{} c.ShouldBindJSON(body) body.UserId, _ = primitive.ObjectIDFromHex(apictx.User.ID) body.UpdateTime = time.Now() body.CreateTime = time.Now() body.Id = primitive.NilObjectID asset = body } if asset != nil { collectionName := dbConf.AssetConf.Collection return repo.RepoDbAddDoc(apictx.CreateRepoCtx(), dbConf.Db.Name, collectionName, asset) } return nil, NewError("不支持的类型") } func AssetProcess(c *gin.Context, apictx *ApiSession, dbConf *model.AssetDbConf, id string) (interface{}, error) { switch dbConf.AssetConf.Type { case model.AssetTypeMesh: return ProcessPackage(apictx, dbConf, id) case model.AssetTypePackage: return ProcessPackage(apictx, dbConf, id) // case model.AssetTypeEnv3d: // return ProcessHdr(apictx, dbConf, id) } return nil, NewError("不支持的类型") } func CreateDatabaseAssetRouter(router *GinRouter) { //dbId的数据上传对应的资产库 router.POSTJWT("/upload/:dbId/:assetConfId", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbId") assetConfId := c.Param("assetConfId") if len(dbId) < 1 || len(assetConfId) < 1 { return nil, NewError("数据Id不合法!") } db, assetConf := repo.GetDatabaseCollection(apictx.CreateRepoCtx(), dbId, assetConfId) if len(db.Name) < 1 || assetConf == nil { return nil, NewError("没有对应的资产定义!") } return UploadAsset2(c, apictx, &model.AssetDbConf{Db: db, AssetConf: assetConf}) }) router.POSTJWT("/updatecomm/:dbid/:assetConfId", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") if len(dbId) < 1 || len(assetConfId) < 1 { return nil, NewError("数据Id不合法!") } db, assetConf := repo.GetDatabaseCollection(apictx.CreateRepoCtx(), dbId, assetConfId) if len(db.Name) < 1 || assetConf == nil { return nil, NewError("没有对应的资产定义!") } return AssetUpdateComm(c, apictx, &model.AssetDbConf{Db: db, AssetConf: assetConf}) }) router.POSTJWT("/updatesource/:dbid/:assetConfId", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") if len(dbId) < 1 || len(assetConfId) < 1 { return nil, NewError("数据Id不合法!") } db, assetConf := repo.GetDatabaseCollection(apictx.CreateRepoCtx(), dbId, assetConfId) if len(db.Name) < 1 || assetConf == nil { return nil, NewError("没有对应的资产定义!") } return AssetUpdateSource(c, apictx, &model.AssetDbConf{Db: db, AssetConf: assetConf}) }) //删除 router.POSTJWT("/delete/:dbid/:assetConfId/:id", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") id := c.Param("id") if len(dbId) < 1 || len(assetConfId) < 1 || len(id) < 1 { return nil, NewError("数据Id不合法!") } db, assetConf := repo.GetDatabaseCollection(apictx.CreateRepoCtx(), dbId, assetConfId) if len(db.Name) < 1 || assetConf == nil { return nil, NewError("没有对应的资产定义!") } return AssetDelete(c, apictx, &model.AssetDbConf{Db: db, AssetConf: assetConf}, id) }) //拷贝 router.POSTJWT("/copy/:dbid/:assetConfId/:id", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") id := c.Param("id") body := &struct { DbId string AssetType string DefineId string OwnerId string OwnerType string }{} err := c.ShouldBindJSON(body) if err != nil { return nil, err } if len(body.DbId) < 1 || len(body.DefineId) < 1 { return nil, NewError("目标库Id不合法") } if len(dbId) < 1 || len(assetConfId) < 1 || len(id) < 1 { return nil, NewError("数据Id不合法!") } fromDbConf := repo.GetDatabaseCollectionSimple(apictx.CreateRepoCtx(), dbId, assetConfId) if fromDbConf == nil { return nil, NewError("没有对应的资产定义!") } toDbConf := repo.GetDatabaseCollectionSimple(apictx.CreateRepoCtx(), body.DbId, body.DefineId) if toDbConf == nil { return nil, NewError("没有对应的资产定义!") } return AssetCopy(c, apictx, fromDbConf, id, toDbConf, body.OwnerId, body.OwnerType, body.AssetType) }) router.POSTJWT("/insertById/:dbid/:assetConfId/:id", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") id := c.Param("id") body := &struct { DbId string DefineId string OwnerId string OwnerType string AssetType string }{} err := c.ShouldBindJSON(body) if err != nil { return nil, err } if len(body.DbId) < 1 || len(body.DefineId) < 1 { return nil, NewError("目标库Id不合法") } if len(dbId) < 1 || len(assetConfId) < 1 || len(id) < 1 { return nil, NewError("数据Id不合法!") } fromDbConf := repo.GetDatabaseCollectionSimple(apictx.CreateRepoCtx(), dbId, assetConfId) if fromDbConf == nil { return nil, NewError("没有对应的资产定义!") } toDbConf := repo.GetDatabaseCollectionSimple(apictx.CreateRepoCtx(), body.DbId, body.DefineId) if toDbConf == nil { return nil, NewError("没有对应的资产定义!") } return AssetCopy2My(c, apictx, fromDbConf, id, toDbConf, body.OwnerId, body.OwnerType, body.AssetType) }) //拷贝 router.POSTJWT("/insert/:dbid/:assetConfId", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") toDbConf := repo.GetDatabaseCollectionSimple(apictx.CreateRepoCtx(), dbId, assetConfId) if toDbConf == nil { return nil, NewError("没有对应的资产定义!") } return InsertAsset(c, apictx, toDbConf) }) //列表查询 router.GETJWT("/list/:dbid/:assetConfId", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") if len(dbId) < 1 || len(assetConfId) < 1 { return nil, NewError("数据Id不合法!") } db, assetConf := repo.GetDatabaseCollection(apictx.CreateRepoCtx(), dbId, assetConfId) if len(db.Name) < 1 || assetConf == nil { return nil, NewError("没有对应的资产定义!") } return AssetList(c, apictx, &model.AssetDbConf{Db: db, AssetConf: assetConf}) }) //公开的列表查询 router.GET("/public/:dbid/:assetConfId", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") if len(dbId) < 1 || len(assetConfId) < 1 { return nil, NewError("数据Id不合法!") } db, assetConf := repo.GetDatabaseCollection(apictx.CreateRepoCtx(), dbId, assetConfId) if len(db.Name) < 1 || assetConf == nil { return nil, NewError("没有对应的资产定义!") } return PublicAssetList(c, apictx, &model.AssetDbConf{Db: db, AssetConf: assetConf}) }) //列表查询 router.GET("/asset/:dbid/:assetConfId", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") if len(dbId) < 1 || len(assetConfId) < 1 { return nil, NewError("数据Id不合法!") } db, assetConf := repo.GetDatabaseCollection(apictx.CreateRepoCtx(), dbId, assetConfId) if len(db.Name) < 1 || assetConf == nil { return nil, NewError("没有对应的资产定义!") } return AssetList(c, apictx, &model.AssetDbConf{Db: db, AssetConf: assetConf}) }) //详情 router.GET("/detail/:dbid/:assetConfId/:id", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") id := c.Param("id") if len(dbId) < 1 || len(assetConfId) < 1 || len(id) < 1 { return nil, NewError("数据Id不合法!") } assetConf := repo.GetDatabaseCollectionSimple(apictx.CreateRepoCtx(), dbId, assetConfId) if assetConf.AssetConf == nil || len(assetConf.Db.Name) < 1 { return nil, NewError("没有对应的资产定义!") } return AssetDetail(c, apictx, assetConf, id) }) //资产处理 router.POSTJWT("/process/:dbid/:assetConfId/:id", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") id := c.Param("id") if len(dbId) < 1 || len(assetConfId) < 1 || len(id) < 1 { return nil, NewError("数据Id不合法!") } db, assetConf := repo.GetDatabaseCollection(apictx.CreateRepoCtx(), dbId, assetConfId) if len(db.Name) < 1 || assetConf == nil { return nil, NewError("没有对应的资产定义!") } return AssetProcess(c, apictx, &model.AssetDbConf{Db: db, AssetConf: assetConf}, id) }) //pack生成阴影 router.POSTJWT("/processshadow/:dbid/:assetConfId/:id", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { dbId := c.Param("dbid") assetConfId := c.Param("assetConfId") id := c.Param("id") body := &struct { Scale int32 Width int32 }{} err := c.ShouldBindJSON(body) if err != nil { body.Scale = 15 body.Width = 512 } if body.Scale < 15 { return nil, NewError("scale需要>=15!") } if len(dbId) < 1 || len(assetConfId) < 1 || len(id) < 1 { return nil, NewError("数据Id不合法!") } assetConf := repo.GetDatabaseCollectionSimple(apictx.CreateRepoCtx(), dbId, assetConfId) if assetConf == nil { return nil, NewError("没有对应的资产定义!") } if assetConf.AssetConf.Type != model.AssetTypePackage && assetConf.AssetConf.Type != model.AssetTypeMesh { return nil, NewError("该类型不支持生成阴影!") } return ProcessPackageShadow(apictx, assetConf, id, body.Scale, body.Width) }) // router.GETJWT("/team/"+asset.Type+"/list", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { // return UserAssetList(c, apictx, targetAsset) // }) // router.GET("/platform/"+asset.Type+"/list", func(c *gin.Context, apictx *ApiSession) (interface{}, error) { // return UserAssetList(c, apictx, targetAsset) // }) } type IteChildren func(n *comm.CategoryNode) []string type FindChild func(n *comm.CategoryNode, id string) []string func FindCategoryIds(c *comm.DbCategory, parents []string) []string { out := []string{} var allChildren IteChildren allChildren = func(n *comm.CategoryNode) []string { ids := []string{} if n == nil { return ids } ids = append(ids, n.Id) if n.Children != nil { for _, c := range n.Children { cids := allChildren(c) if len(cids) > 0 { ids = append(ids, cids...) } } } return ids } var findChildrens FindChild findChildrens = func(n *comm.CategoryNode, id string) []string { ids := []string{} if n == nil { return ids } if n.Id == id { ids = allChildren(n) return ids } if n.Children == nil { return ids } //查找孩子节点 for _, c := range n.Children { ids = findChildrens(c, id) if len(ids) > 0 { break } } return ids } for _, v := range parents { for _, catnode := range c.Categories { extends := findChildrens(catnode, v) if len(extends) > 0 { out = append(out, extends...) break } } } return out } func ParseCategories(query map[string]interface{}, apictx *ApiSession, dbConf *model.AssetDbConf) error { filters := []bson.M{} keyfilters := []bson.M{} //keyword if query["keyword"] != nil { keyword := query["keyword"].(string) if len(keyword) > 0 { keyfilters = append(keyfilters, bson.M{"name": bson.M{"$regex": keyword, "$options": "$i"}}) keyfilters = append(keyfilters, bson.M{"cusNum": bson.M{"$regex": keyword, "$options": "$i"}}) filters = append(filters, bson.M{"$or": keyfilters}) } query["keyword"] = nil } if query["cusCategories"] != nil && query["cateId"] != nil { categories := query["categories"].([]interface{}) cateId := query["cateId"].(string) //查询所有子内容 if len(categories) > 0 { cateConf := &comm.DbCategory{} filterCaties := []string{} //查询用户的 ok, _ := repo.RepoSeachDoc(apictx.CreateRepoCtx(), &repo.DocSearchOptions{CollectName: repo.CollectionCategories, Query: repo.Map{"_id": cateId}}, cateConf) if !ok { return NewError("cate get error") } for _, c := range categories { filterCaties = append(filterCaties, c.(string)) } extends := FindCategoryIds(cateConf, filterCaties) if len(extends) > 0 { filter := bson.M{"categories": bson.M{"$elemMatch": bson.M{"$in": extends}}} filters = append(filters, filter) } } query["cusCategories"] = nil query["cateId"] = nil } if query["categories"] != nil && dbConf.Db.Categories != nil { categories := query["categories"].([]interface{}) //查询所有子内容 if len(categories) > 0 { cateConf := dbConf.Db.Categories filterCaties := []string{} for _, c := range categories { filterCaties = append(filterCaties, c.(string)) } extends := FindCategoryIds(cateConf, filterCaties) if len(extends) > 0 { filter := bson.M{"categories": bson.M{"$elemMatch": bson.M{"$in": extends}}} filters = append(filters, filter) } } query["categories"] = nil } if len(filters) > 0 { query["$and"] = filters } return nil }