Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Meteor Collection: find element in array

Tags:

mongodb

meteor

I have no experience with NoSQL. So, I think, if I just try to ask about the code, my question can be incorrect. Instead, let me explain my problem.

Suppose I have e-store. I have catalogs

Catalogs = new Mongo.Collection('catalogs);

and products in that catalogs

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

Then, people add there orders to temporary collection

Order = new Mongo.Collection();

Then, people submit their comments, phone, etc and order. I save it to collection Operations:

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

Nice, but when i want to get stats by every product, in what Operations product have used. How can I search thru my Operations and find every operation with that product?

Or this way is bad? How real pro's made this in real world?

like image 483
Deromanenko Avatar asked Feb 10 '23 23:02

Deromanenko


2 Answers

If I understand it well, here is a sample document as stored in your Operation collection:

{
  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" },
      ]
  }
},

Given that, to find all operations having item reference XYZ001 you simply have to query:

> db.operations.find({"savedOrder.lines.itemRef":"XYZ001"})

This will return the whole document. If instead you are only interested in the client reference (and operation _id), you will use a projection as an extra argument to find:

> db.operations.find({"savedOrder.lines.itemRef":"XYZ001"}, {"clientRef": 1})
{ "_id" : ObjectId("556f07b5d5f2fb3f94b8c179"), "clientRef" : "john-001" }
{ "_id" : ObjectId("556f07b5d5f2fb3f94b8c17a"), "clientRef" : "paul-002" }

If you need to perform multi-documents (incl. multi-embedded documents) operations, you should take a look at the aggregation framework:

For example, to calculate the total of an order:

> 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 }
like image 192
Sylvain Leroux Avatar answered Feb 27 '23 02:02

Sylvain Leroux


I'm an eternal newbie, but since no answer is posted, I'll give it a try.

First, start by installing robomongo or a similar software, it will allow you to have a look at your collections directly in mongoDB (btw, the default port is 3001)

The way I deal with your kind of problem is by using the _id field. It is a field automatically generated by mongoDB, and you can safely use it as an ID for any item in your collections.

Your catalog collection should have a string array field called product where you find all your products collection items _id. Same thing for the operations: if an order is an array of products _id, you can do the same and store this array of products _id in your savedOrder field. Feel free to add more fields in savedOrder if necessary, e.g. you make an array of objects products with additional fields such as discount.

Concerning your queries code, I assume you will find all you need on the web as soon as you figure out what your structure is.

For example, if you have a product array in your savedorder array, you can pull it out like that:

Operations.find({_id: "your operation ID"},{"savedOrder.products":1)

Basically, you ask for all the products _id in a specific operation. If you have several savedOrders in only one operation, you can specify too the savedOrder _id, if you used the one you had in your local collection.

Operations.find({_id: "your_operation_ID", "savedOrder._id": "your_savedOrder_ID"},{"savedOrder.products":1)

ps: to bad-ass coders here, if I'm doing it wrong, please tell me.

like image 36
Billybobbonnet Avatar answered Feb 27 '23 00:02

Billybobbonnet