- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
假设我们有 2 个集合:“users”
和 “posts”
,由以下类型建模:
type User struct {
ID string `bson:"_id"`
Name string `bson:"name"`
Registered time.Time `bson:"registered"`
}
type Post struct {
ID string `bson:"_id"`
UserID string `bson:"userID"`
Content string `bson:"content"`
Date time.Time `bson:"date"`
}
这些可以在存储/检索单个甚至文档集合时使用,例如:
usersColl := sess.DB("").C("users")
postsColl := sess.DB("").C("posts")
// Insert new user:
u := &User{
ID: "1",
Name: "Bob",
Registered: time.Now(),
},
err := usersColl.Insert(u)
// Handle err
// Get Posts in the last 10 mintes:
var posts []*Post
err := postsColl.Find(
bson.M{"date": bson.M{"$gt": time.Now().Add(-10 * time.Minute)}},
).Limit(20).All(&posts)
// Handle err
如果我们使用 aggregation 会怎样?获取这些文件的混合物?例如Collection.Pipe()
:
// Query users with their posts:
pipe := collUsers.Pipe([]bson.M{
{
"$lookup": bson.M{
"from": "posts",
"localField": "_id",
"foreignField": "userID",
"as": "posts",
},
},
})
var doc bson.M
it := pipe.Iter()
for it.Next(&doc) {
fmt.Println(doc)
}
// Handle it.Err()
我们在单个查询中查询用户的帖子。结果是用户和帖子的混合体。我们如何重用我们的 User
和 Post
模型类型,而不必将结果作为“原始”文档(bson.M
类型)处理)?
最佳答案
上面的查询返回“几乎”匹配 User
文档的文档,但它们也有每个用户的帖子。所以基本上结果是一系列 User
文档,带有 Post
数组或 slice 嵌入。
一种方法是将 Posts []*Post
字段添加到 User
本身,这样我们就完成了:
type User struct {
ID string `bson:"_id"`
Name string `bson:"name"`
Registered time.Time `bson:"registered"`
Posts []*Post `bson:"posts,omitempty"`
}
虽然这可行,但仅仅为了单个查询而使用 Posts
扩展 User
似乎“矫枉过正”。如果我们继续沿着这条路走下去,我们的 User
类型会变得臃肿,因为有很多用于不同查询的“额外”字段。更不用说如果我们填写 Posts
字段并保存用户,这些帖子最终会保存在 User
文档中。不是我们想要的。
另一种方法是创建一个 UserWithPosts
类型复制 User
,并添加一个 Posts []*Post
字段。不用说这是丑陋和不灵活的(对 User
所做的任何更改都必须手动反射(reflect)到 UserWithPosts
)。
我们可以利用 struct embedding 而不是修改原始的 User
,也不是从“scratch”创建新的 UserWithPosts
类型。 (重用现有的 User
和 Post
类型)有一个小技巧:
type UserWithPosts struct {
User `bson:",inline"`
Posts []*Post `bson:"posts"`
}
注意 bson tag value ",内联"
。这记录在 bson.Marshal()
和 bson.Unmarshal()
(我们将用它来解码):
inline Inline the field, which must be a struct or a map.
Inlined structs are handled as if its fields were part
of the outer struct. An inlined map causes keys that do
not match any other struct field to be inserted in the
map rather than being discarded as usual.
通过使用嵌入和 ",inline"
标签值,UserWithPosts
类型本身将成为解码 User
文档的有效目标,及其 Post []*Post
字段将是查找 “posts”
的完美选择。
使用它:
var uwp *UserWithPosts
it := pipe.Iter()
for it.Next(&uwp) {
// Use uwp:
fmt.Println(uwp)
}
// Handle it.Err()
或者一步得到所有结果:
var uwps []*UserWithPosts
err := pipe.All(&uwps)
// Handle error
UserWithPosts
的类型声明可能是也可能不是局部声明。如果您在其他地方不需要它,它可以是您执行和处理聚合查询的函数中的局部声明,因此它不会使您现有的类型和声明膨胀。如果你想重用它,你可以在包级别声明它(导出或未导出),并在你需要的任何地方使用它。
另一种选择是使用 MongoDB 的 $replaceRoot
“重新排列”结果文档,因此“简单”结构将完美覆盖文档:
// Query users with their posts:
pipe := collUsers.Pipe([]bson.M{
{
"$lookup": bson.M{
"from": "posts",
"localField": "_id",
"foreignField": "userID",
"as": "posts",
},
},
{
"$replaceRoot": bson.M{
"newRoot": bson.M{
"user": "$$ROOT",
"posts": "$posts",
},
},
},
})
通过这种重新映射,结果文档可以像这样建模:
type UserWithPosts struct {
User *User `bson:"user"`
Posts []*Post `bson:"posts"`
}
请注意,虽然这有效,但所有文档的 posts
字段将从服务器获取两次:一次作为返回文档的 posts
字段,另一次作为用户
字段;我们不映射/使用它,但它存在于结果文档中。因此,如果选择此解决方案,则应删除 user.posts
字段,例如使用 $project
阶段:
pipe := collUsers.Pipe([]bson.M{
{
"$lookup": bson.M{
"from": "posts",
"localField": "_id",
"foreignField": "userID",
"as": "posts",
},
},
{
"$replaceRoot": bson.M{
"newRoot": bson.M{
"user": "$$ROOT",
"posts": "$posts",
},
},
},
{"$project": bson.M{"user.posts": 0}},
})
关于mongodb - Mgo 聚集体 : how to reuse model types to query and unmarshal "mixed" results?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46774424/
程序集,masm 嘿,我写了宏来打印存储在 dane1 段中的 1 字节值。 我将值除以 16,然后将提醒推送到堆栈,直到值==0。然后我弹出提醒将它们转换为 ASCII 码,并打印它们。 有人可以看
我在 Apache Geronimo 2.1.3 上有一个 Web 服务应用程序。 我正在使用 JAX-WS,使用 SOAP 1.1 注释 POJOS。 (使用 Sun JDK 1.5) 各种客户端都
我有一个数据变量,monthArray,它被多个消费者读取,并由单个定期更新程序线程定期更新数据。全部异步。 我已经考虑了这两个选项来安全地执行更新。 ArrayList tempArray
我有一组 3D 体。每个 Body 由 8 个点定义,每个点具有三个坐标。所有的物体都是立方体的或近似立方体的。我想用系统的点栅格“填充”立方体。坐标存储在简单的 data.frames 中。 我开发
我正在处理遗留代码,需要打补丁。 问题:一个古老的应用程序发送错误的 HTTP POST 请求。其中一个参数未经过 URL 编码。我知道这个参数总是排在最后而且我知道它的名字。我现在正尝试在运行在 t
我想在触摸屏幕时移动 sprite body ,但它不能发生...... -(void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
这个问题在这里已经有了答案: Can a union be initialized in the declaration? (3 个答案) 关闭 7 年前。 如果它是一个struct那么它就可以完成
我正在尝试获取生成 sigsys 信号的系统调用的地址!但我从 gcc 收到以下错误: gcc emulator.c -fms-extensions error: ‘siginfo_t’ has no
当我使用 Postman 进行 API 调用时,我收到一个 JSON 对象..这是我所期望的。 但是,当我像这样与 Guzzle 进行相同的调用时: $client = new \GuzzleHttp
在编码时,出现了差异。通常在编写简单的方法或构造函数时,我经常使用表达式体技术。但是,当我产生以下内容时: public class Sample : ISample { private r
我正在使用 LibGDX 创建一个新项目。 我想做的是,我将 tmx 文件中的主体加载到工作正常的关卡中。尸体也有一个 Sprite 。 问题是,我想让用户触摸场景中的某些 body 。当他们触摸 b
我的意图:在不使用 union 的情况下循环遍历一个结构的 30 个成员,所有成员都是字符数组类型,每个成员都存储对 itoa 的调用结果。在下面的代码中,我将结构体成员命名为a-z、A-D。在调用函
我必须将我的代码段之一从 C 转换为 java。代码如下。 union commandString{ char commndStr[20]; struct{ char
#include union NumericType { float value; int intvalue; }Values; int main() { Values.va
我在此代码中收到错误: fun num(num:Int):Int { if (num > 0){ print(num % 10) return num / 10
我是一名优秀的程序员,十分优秀!