草庐IT

javascript - MongoDb:如何从文档中获取字段(子文档)?

coder 2023-10-30 原文

考虑以下示例集合:

 {
    "_id:"0,
    "firstname":"Tom",
    "children" : {
                    "childA":{
                                "toys":{
                                        'toy 1':'batman',
                                        'toy 2':'car',
                                        'toy 3':'train',
                                        }
                                "movies": {
                                        'movie 1': "Ironman"
                                        'movie 2': "Deathwish"
                                        }
                                },
                    "childB":{
                                "toys":{
                                        'toy 1':'doll',
                                        'toy 2':'bike',
                                        'toy 3':'xbox',
                                        }
                                "movies": {
                                        'movie 1': "Frozen"
                                        'movie 2': "Barbie"
                                        }
                                }
                    }
}

现在,我只想检索特定文档中的电影。

我已经尝试过这样的事情:
movies = users.find_one({'_id': 0}, {'_id': 0, 'children.ChildA.movies': 1})

但是,我了解了从“ child ”到“电影”的整个 Realm 结构,这是内容。我该如何查询并仅检索“电影”的内容?

具体来说,我想以此结束:
                                       {
                                        'movie 1': "Frozen"
                                        'movie 2': "Barbie"
                                        }

最佳答案

这里的问题是您当前的数据结构对于查询而言确实不是很好。这主要是因为您使用的是“键”来实际表示“数据点”,尽管最初看起来似乎是一个合理的想法,但这实际上是一个非常糟糕的做法。

因此,与其做诸如将“childA”和“childB”分配为对象或“子文档”的键之类的事情,不如将这些“值”分配给通用键名,例如:

 {
    "_id:"0,
    "firstname":"Tom",
    "children" : [
        { 
            "name": "childA", 
            "toys": [
                "batman",
                "car",
                "train"
            ],
            "movies": [
                "Ironman"
                "Deathwish"
            ]
        },
        {
            "name": "childB",
            "toys": [
                "doll",
                "bike",
                "xbox",
            ],
            "movies": [
                "Frozen",
                "Barbie"
            ]
        }
    ]
}

这不是最好的方法,因为存在嵌套数组,这可能是一个潜在的问题,但是对此也有解决方法(但稍后),但是这里要点是,这比在“键”中定义数据要好得多。而且,未统一命名的“键”的主要问题在于,MongoDB通常不允许使用任何通配符“通配”这些名称,因此您必须使用命名和“绝对路径”来访问元素,如下所示:

children -> childA -> toys
children -> childB -> toys



简而言之是不好的,并与之相比:

"children.toys"

从上面准备的样本中,然后我想说这是组织数据的更好的方法。

即使这样,对于MongoDB中的标准.find()类型查询,仅获取诸如“电影的唯一列表”之类的内容也不在话下。实际上,这需要更多的“文档操作”,并且在MongoDB的聚合框架中得到了很好的支持。它具有查询方法中不存在的丰富的操作功能,对于具有上述结构的每个文档,您可以执行以下操作:

db.collection.aggregate([
    # De-normalize the array content first
    { "$unwind": "$children" },

    # De-normalize the content from the inner array as well
    { "$unwind": "$children.movies" },

    # Group back, well optionally, but just the "movies" per document
    { "$group": {
        "_id": "$_id",
        "movies": { "$addToSet": "$children.movies" }
    }}
])

因此,现在文档中的“列表”响应仅包含“独特”电影,这更符合您的要求。另外,您也可以只使用 $push 并制作一个“非唯一”列表。但愚蠢的是,实际上是这样的:

db.collection.find({},{ "_id": False, "children.movies": True })

作为一个“范围广泛的”概念,那么您可以通过简单地使用.distinct()方法将其简化很多。基本上根据您提供的输入形成“独特”键的列表。这可以很好地与数组一起玩:

db.collection.distinct("children.toys")

从本质上讲,这是对集合中每个“玩具”值的所有“不同”事件的集合范围分析,并以简单的“数组”形式返回。

但是,对于您现有的结构,它应该有一个解决方案来解释,但是您确实必须理解该解释是可怕的。这里的问题是,通用查询和聚合方法可用的“本机”和优化方法根本不可用,唯一可用的选项是基于JavaScript的处理。与“本地代码”方法相比,即使通过“v8”引擎集成稍好一点,但实际上仍然是完整的懒散的

因此,从您拥有的“原始”表单中(JavaScript表单,函数必须非常易于翻译”):

 db.collection.mapReduce(
     // Mapper
     function() {
         var id this._id;
             children = this.children;

         Object.keys(children).forEach(function(child) {
             Object.keys(child).forEach(function(childKey) {
                 Object.keys(childKey).forEach(function(toy) {
                     emit(
                         id, { "toys": [children[childkey]["toys"][toy]] }
                     );
                 });
             });
         });
     },
     // Reducer
     function(key,values) {
         var output = { "toys": [] };

         values.forEach(function(value) {
             value.toys.forEach(function(toy) {
                 if ( ouput.toys.indexOf( toy ) == -1 )
                     output.toys.push( toy );
             });
         });
     },
     {
         "out": { "inline": 1 }
     }
)

因此,JavaScript评估是一种“可怕”的方法,因为它的执行速度要慢得多,并且您会看到需要实现的“遍历”代码。对性能而言是个坏消息,所以不要这样做。改为更改结构。

最后,您可以对此模型进行建模以避免“嵌套数组”的概念。并且了解和nest_rstrong唯一真正的问题是“嵌套数组”是,如果不阅读整个文档并对其进行修改,则“更新”嵌套元素实际上是不可能的。

因此, $push $pull 方法可以正常工作。但是使用“位置” $运算符只是不起作用,因为“外部”数组索引始终是“第一个”匹配元素。因此,如果这确实是您的问题,则可以执行以下操作,例如:

 {
    "_id:"0,
    "firstname":"Tom",
    "childtoys" : [
        { 
            "name": "childA", 
            "toy": "batman"
        }.
        { 
            "name": "childA",
            "toy": "car"
        },
        {
            "name": "childA",
            "toy": "train"
        },
        {
            "name": "childB",
            "toy": "doll"
        },
        {
            "name": "childB",
            "toy": "bike"
        },
        {
            "name": "childB",
            "toy": "xbox"
        }
    ],
    "childMovies": [
        {
             "name": "childA"
             "movie": "Ironman"
       },
       {
            "name": "childA",
            "movie": "Deathwish"
       },
       {
            "name": "childB",
            "movie": "Frozen"
       },
       {
            "name": "childB",
            "movie": "Barbie"
       }
  ]
}

如果确实确实需要定期“更新”项目,而不仅仅是将“push”和“pull”项添加到“toys”和“movies”数组中,那将是避免嵌套更新的一种方法。

但是这里的总体信息是围绕您实际使用的访问模式来设计数据。在能够查询或以其他方式灵活地发布更新方面,MongoDB通常不喜欢带有“严格路径”的事物。

关于javascript - MongoDb:如何从文档中获取字段(子文档)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25909927/

有关javascript - MongoDb:如何从文档中获取字段(子文档)?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  5. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  6. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  7. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  8. ruby - 如何每月在 Heroku 运行一次 Scheduler 插件? - 2

    在选择我想要运行操作的频率时,唯一的选项是“每天”、“每小时”和“每10分钟”。谢谢!我想为我的Rails3.1应用程序运行调度程序。 最佳答案 这不是一个优雅的解决方案,但您可以安排它每天运行,并在实际开始工作之前检查日期是否为当月的第一天。 关于ruby-如何每月在Heroku运行一次Scheduler插件?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/8692687/

  9. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  10. ruby - 如何使用文字标量样式在 YAML 中转储字符串? - 2

    我有一大串格式化数据(例如JSON),我想使用Psychinruby​​同时保留格式转储到YAML。基本上,我希望JSON使用literalstyle出现在YAML中:---json:|{"page":1,"results":["item","another"],"total_pages":0}但是,当我使用YAML.dump时,它不使用文字样式。我得到这样的东西:---json:!"{\n\"page\":1,\n\"results\":[\n\"item\",\"another\"\n],\n\"total_pages\":0\n}\n"我如何告诉Psych以想要的样式转储标量?解

随机推荐