Meteor集合:在数组中查找元素

4

我对NoSQL没有经验。因此,如果我只是尝试询问代码,我的问题可能会不正确。相反,让我解释一下我的问题。

假设我有一个电子商店,我有目录

Catalogs = new Mongo.Collection('catalogs);

以及目录中的产品

Products = new Mongo.Collection('products');

然后,人们将他们的订单添加到临时收藏中。
Order = new Mongo.Collection();

接下来,人们提交他们的评论、电话等信息并下单。我将其保存到操作集合中:

Operations.insert({
  phone: "phone",
  comment: "comment",
  etc: "etc"
  savedOrder: Order //<- Array, right? Or Object will be better?
});

很好,但是当我想要按每个产品获取统计信息时,产品使用了哪些操作。我该如何搜索我的操作并找到使用该产品的每个操作?
或者这种方式不好吗?真正的专业人士在现实世界中是如何做到这一点的?
3个回答

7
如果我理解得正确,这是一个存储在您的Operation集合中的示例文档:
{
  clientRef: "john-001",
  phone: "12345678",
  other: "etc.",
  savedOrder: {
      "someMetadataAboutOrder": "...",
      "lines" : [
          { qty: 1, itemRef: "XYZ001", unitPriceInCts: 1050, desc: "USB Pen Drive 8G" },
          { qty: 1, itemRef: "ABC002", unitPriceInCts: 19995, desc: "Entry level motherboard" },
      ]
  }
},
{
  clientRef: "paul-002",
  phone: null,
  other: "etc.",
  savedOrder: {
      "someMetadataAboutOrder": "...",
      "lines" : [
          { qty: 3, itemRef: "XYZ001", unitPriceInCts: 950, desc: "USB Pen Drive 8G" },
      ]
  }
},

考虑到这一点,要查找所有引用项目为XYZ001的操作,你只需查询:
> db.operations.find({"savedOrder.lines.itemRef":"XYZ001"})

这将返回整个文档。如果您只对客户端引用(以及操作 _id)感兴趣,您可以在find的额外参数中使用投影
> db.operations.find({"savedOrder.lines.itemRef":"XYZ001"}, {"clientRef": 1})
{ "_id" : ObjectId("556f07b5d5f2fb3f94b8c179"), "clientRef" : "john-001" }
{ "_id" : ObjectId("556f07b5d5f2fb3f94b8c17a"), "clientRef" : "paul-002" }

如果您需要执行多文档(包括多嵌套文档)操作,您应该查看聚合框架
例如,计算订单的总数:
> db.operations.aggregate([
  {$match: { "_id" : ObjectId("556f07b5d5f2fb3f94b8c179") }},
  {$unwind: "$savedOrder.lines" },
  {$group: { _id: "$_id", 
             total: {$sum: {$multiply: ["$savedOrder.lines.qty", 
                                        "$savedOrder.lines.unitPriceInCts"]}}
  }}
])
{ "_id" : ObjectId("556f07b5d5f2fb3f94b8c179"), "total" : 21045 }

大师之触。谢谢你,Sylvain,你的方法肯定更好。对于我这个Mongo经验不足的人来说,即使是简单的事情也会让我感到困惑。 :) - Capybarro

1

我是一个永远的新手,但由于没有答案发布,我会尝试一下。

首先,安装robomongo或类似软件,它将允许您直接在mongoDB中查看集合(默认端口为3001)

我处理您这种问题的方式是使用_id字段。它是由mongoDB自动生成的字段,您可以放心地将其用作集合中任何项目的ID。

您的catalog集合应该有一个名为product的字符串数组字段,其中包含您所有产品集合项的_id。对于操作也是同样的道理:如果订单是产品_id的数组,则您可以执行相同的操作,并将此产品_id数组存储在savedOrder字段中。如有必要,可以随意添加更多的savedOrder字段,例如制作一个对象数组products,其中包含其他字段,如discount

关于您的查询代码,我假设只要您弄清楚了结构,就可以在网络上找到所需的全部内容。

例如,如果您在savedorder数组中有一个产品数组,您可以像这样取出它:
Operations.find({_id: "your operation ID"},{"savedOrder.products":1)

基本上,您可以在特定操作中请求所有产品的_id。如果您在一个操作中有多个savedOrders,则还可以指定savedOrder _id,如果您在本地集合中使用了一个,则需要指定该ID。
Operations.find({_id: "your_operation_ID", "savedOrder._id": "your_savedOrder_ID"},{"savedOrder.products":1)

PS:如果我做错了,请各位高手指出。


非常感谢你,Billy!我不太明白如何应用你的建议,但是你给了我灵感 :) - Capybarro

0

我找到了答案 :) 当然,这对于真正的专业人士来说并不是一个揭示,但对我来说是一个很大的进步。也许我的经验对某些人有用。所有的魔法都在于使用正确的Mongo操作符。让我们用伪代码来解决这个问题。

我们有这样一个结构:

Operations:
  1. Operation: {
    _id: <- Mongo create this unique for us
    phone: "phone1",
    comment: "comment1",
    savedOrder: [
    {
      _id: <- and again
      productId: <- whe should save our product ID from 'products' 
      name: "Banana",
      quantity: 100
    },
    {
      _id:,
      productId: <- Another ID, that we should save if order 
      name: "apple",
      quantity: 50
    }
    ]

如果我们想知道用户在哪个操作中选择了“香蕉”,我们应该使用mongoDB运算符“elemMatch”{{link1:在Mongo文档中}}

db.getCollection('operations').find({}, {savedOrder: {$elemMatch:{productId: "f5mhs8c2pLnNNiC5v"}}});

简单来说,我们获取保存订单的文档,其中包含我们想要查找的产品ID。我不知道这是否是最好的方法,但对我来说它有效 :) 谢谢!

从数据库的角度来看,我认为您不需要在此处的嵌入式文档中使用“_id”,因为“productId”应该足以区分各个订单行(您不需要为相同的“productId”使用两行,对吧?) - Sylvain Leroux

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接