我应该从:我对MongoDB以及文档样式的数据库一般都知道。
我有一个看起来像这样的集合:
{
"_id" : ObjectId("554a5e72b16f31ff0894310e"),
"title" : "ABC",
"admins" : [
"personA",
"personB",
],
"email_address" : "ABC@mysite.com"
}
{
"_id" : ObjectId("554a5e72b16f31ff0894310f"),
"title" : "Junk Site",
"admins" : [
"personA",
"personB"
],
"email_address" : "garbage@mysite.com"
}
{
"_id" : ObjectId("554a5e72b16f31ff08943110"),
"title" : "Company Three Site",
"admins" : [
"personC"
"personD",
],
"email_address" : "company2plus1@mysite.com"
}
我需要做的是将Company One
的管理员列表附加到Company Three
,以便Company Three
现在有四位管理员(A,B,C,D)。
我尝试了以下内容,因为它对我来说非常简单 - 从原点获取数据并直接附加到目的地:
db.runCommand({
findAndModify : 'sites',
query : {'title' : 'Company Three Site'},
update : { '$addToSet' :
{'admins' :
db.projects.find({'title' : 'ABC'}, {'_id' : 0, 'admins' : 1}
}
}
})
但是,这不能正常工作。
我仍在试图找出直接做到这一点的方法,但问题是......
1)使用单个命令甚至可以实现这一点,还是需要将其拆分? 2)我的逻辑思路是否有意义,或者我是否应该采用其他更简单的方式对MongoDB风格的数据库更常规?
答案 0 :(得分:2)
原子更新无法做到这一点。但是,解决方法是使用find()
方法查询源集合,并使用游标的forEach()
方法迭代结果,获取数组并使用$addToSet
运算符更新目标集合和$each
修饰符。
让我们通过插入测试集合的上述示例文档来证明这一点:
#include <iostream>
#include <string>
class LibraryInterface {
public:
std::string name;
std::string name1;
std::string name2;
std::string name3;
std::string name4;
std::string name5;
std::string name6;
};
class Library : private LibraryInterface
{
public:
Library() {name="BOB";}
private:
LibraryInterface* getLibraryInterface() {return this;} //only LibraryCustomer can aquire the interface pointer
friend class LibraryCustomer;
};
class LibraryCustomer
{
protected:
LibraryInterface* getLibraryInterface(Library& lib) {return lib.getLibraryInterface();} //only things deriving from LibraryCustomer can aquire the interface pointer
};
class Kid : public LibraryCustomer
{
public:
void function(Library& lib) {
LibraryInterface* interface = getLibraryInterface(lib);
std::cout << interface->name;
}
};
int main() {
Library lib;
Kid k;
k.function(lib);
}
以下操作会将公司“ABC”中的admins数组元素添加到公司“Company Three Site”管理数组中:
db.test.insert([
{
"title" : "ABC",
"admins" : [
"personA",
"personB"
],
"email_address" : "ABC@mysite.com"
},
{
"title" : "Junk Site",
"admins" : [
"personA",
"personB"
],
"email_address" : "garbage@mysite.com"
},
{
"title" : "Company Three Site",
"admins" : [
"personC",
"personD"
],
"email_address" : "company2plus1@mysite.com"
}
])
使用公司“公司三站点”db.test.find({"title" : "ABC"}).forEach(function (doc){
var admins = doc.admins;
db.test.update(
{"title" : "Company Three Site"},
{
"$addToSet": {
"admins": { "$each": admins }
}
},
{ "multi": true }
);
});
将产生:
db.collection.find({"title" : "Company Three Site"});
答案 1 :(得分:2)
db.projects.find
实际上会返回一个游标,您绝对不希望将其添加到您的集合中。由于您事先知道您将只找到一个值,因此您可以使用.next().admin
专门从光标中获取属性 - 但请记住,仅可以使用从.find
返回的第一个值。否则,我认为你将不得不使用循环。
$addToSet
也会将数组添加为一个整体,因此您必须append multiple values using $each
所有在一起:
db.runCommand({
findAndModify: 'sites',
query: {'title': 'Company Three Site'},
update: {
$addToSet: {
"admins": {
$each: db.projects.find(
{"title": "ABC"},
{"_id": 0, "admins": 1}
).next().admins
}
}
}
})