How to store Invoice Items in MongoDB? [duplicate] - mongodb

This question already has answers here:
MongoDB relationships: embed or reference?
(10 answers)
Mongoose populate vs object nesting
(1 answer)
Closed 3 years ago.
I've to store line items in the database.
Currently, I'm creating a batch of them and storing it as a single document.
date: null,
items: [
{ name: 'Bla', cost: 5, ref: 'user id' },
{ name: 'Bla', cost: 5, ref: 'user id' },
]
But I'm having a gut feeling that it will be more costly (performance and processing) because it is an array of object. ($unwind, $project).
Will it be good if I store each line item as a document instead?
The reason why I've not done so far is we may have around 1 billion documents in 1-3 years.
Once more thing, how can I generate a unique ID for each line item? I know Mongo generates _id, but I mean a number 0, 1, 2, etc. which can be shown in invoices.
So, I'm not sure if MongoDB can handle it effectively.
Best,
Faheem
EDIT:
These are the reasons that I think this question is not a duplicate to the suggested duplicates.
Those questions are referring to ref vs embedding the document. I'm not.
The question is what will be the best way (in terms of performance and low latency) to store inline items, in a batch (array of object) or as a single document. I'm not concerned about references or anything here.

Related

Check if document exists in different collection MongoDB Aggregation [duplicate]

This question already has an answer here:
How to Model a "likes" voting system with MongoDB
(1 answer)
Closed 6 years ago.
I insert a new document in Votes collection when a user votes on a poll.
{
_id: ObjectId(XXX),
card: 11,
user: 22
}
Now when a user requests for all the polls I want to return a Voted: 1 field if the users have already voted on the poll i.e. a document is already present in the Votes collection.
Can anyone tell me if there's a way to access documents from another collection in aggregation command.
With mongoDB it's not possible to access multiple documents within a query. You should change your data model and add an array or use embedded documents.
I don't know much about your use case so please take this just as an example and not as a final solution.
The following model contains an array for all voted polls of an user. Therefore you can check if the array contains the poll and return 1 if its true.
{
_id: ObjectId(XXX),
user: 22,
cards: [1, 3, 5]
}
See https://docs.mongodb.org/manual/core/data-modeling-introduction/ for more details about data modelling in mongoDB.

Mongo find and rank result [duplicate]

This question already has answers here:
In MongoDB search in an array and sort by number of matches
(2 answers)
Closed 7 years ago.
I have a mongo collection that has docs similar to the schema below. And I have a ui from which a user could filter on the attributes (using logical or). Since its using OR I want the results to be ordered such that I first get the ones that match the most filters. For example: if i filter on author "auth1" and "tag1" I get back both records but the second record is on top. In this example I just have 2 attr to filter on, but there are about 20.
Do you have any suggestions of the best way of tackling this? I was thinking of writing a map-reduce query to compute the "match rank".
{name: "bookName", tags:["tag1"], authors: [] }
{name: "bookName2", tags:["tag1", "tag2"], authors: ["auth1", "auth2"] }
If I understand your proble, You wants sort the result By authors.length and tags.length.
The problem, in MongoDB (I test on 2.6) with the sort(), it is impossible to sort by two parallels arrays. You can sort by album.length or tags.length but not both.
// sort By max to min authors
db.getCollection('rank').find({}).sort({ authors : -1 });
// sort by max to min tags
db.getCollection('rank').find({}).sort({ tags : -1 });
If you watn sort your result by both of them, you should use the Aggregation Framework. You have a great explanation here : https://stackoverflow.com/a/9040269/1506914
It is possible using Aggregation Framework. Have a look at this question, it's similar to yours.

Ensure each element in an array of objects contains a unique value for a key [duplicate]

This question already has answers here:
Mongoose Unique values in nested array of objects
(2 answers)
Closed 7 years ago.
I have a mongo collection like so:
{
_id: 'asdasdasd',
battletag: 'battletag#1290',
games: [{
id: "somegameid",
name: "Starcraft II",
characters: ['corvid'],
groups: ['Husky Starcraft']
}, {
id: "someothergameid",
name: "World of Warcraft",
characters: ['corvid', 'crow', 'crowtoe'],
groups: ['Warlords of Draenor']
}]
}
I want to ensure that, for every game in games, the id attribute is unique. Is there a way to ensure uniqueness on values in arrays of objects in mongodb?
You should rely on mongoDB built-in _id. Create another collection with all the games, and refer to it using its documents _id in the Games array of your collection. You can still store all data not directly related to the game in the Games array, along with the game _id

In MongoDB, when to use a simple subdocument, when an array with 2-field elements?

Background
I am storing table rows as MongoDb documents, with each column having a name. Let's say table has these columns of interest: Identifier, Person, Date, Count. The MongoDb document also has some extra fields separate from the table data, represented by timestamp. Columns are not fixed (which is why I use schema-free database to store them in the first place).
There will be need to do various complex, but so far unspecified queries. I am not very concerned about performance, though query performance may conceivably become a bottleneck. Once inserted, documents will not be modifed (a new document with same Identifier will be created instead), and insertions are not very frequent (let's say, 1000 new MongoDb documents per day). So amount of data will steadily grow over time.
Example
The straight-forward approach is having a collection of MongoDb documents like:
{
_id: XXXX,
insertDate: ISODate("2012-10-15T21:26:17Z"),
flag: true,
data: {
Identifier: "AB002",
Person: "John002",
Date: ISODate("2013-11-16T21:26:17Z"),
Count: 1
}
}
Now I have seen an alternative approach (for example in accepted answer of this question), using array with two fields per object:
{
_id: XXXX,
insertDate: ISODate("2012-10-15T21:26:17Z"),
flag: true,
data: [
{ field: "Identifier", value: "AB002" },
{ field: "Person", value: "John001" },
{ field: "Date", value: ISODate("2013-11-16T21:26:17Z") },
{ field: "Count", value: 1 }
]
}
Questions
Does the 2nd approach make any sense at all?
If yes, then how to choose which to use? Especially, are there some specific kinds of queries which are easy/cheap with one approach, hard/costly with another? Any "rules of thumb" on which way to go, or pro-con lists for both? Example real-life cases of one aproach being inconvenient would be especially valuable.
In your specific example the First version is a lot more appropriate and simple. You have to think in terms of how you would query your document.
It is a lot simpler to query your database like this: db.collection.find({"data.Identifier": "AB002"})
Although I'm not 100% sure why you even need the inner document. Why can't structure your document like:
{
_id: "AB002",
insertDate: ISODate("2012-10-15T21:26:17Z"),
flag: true,
Person: "John002",
Date: ISODate("2013-11-16T21:26:17Z"),
Count: 1
}
Pros of first example:
Simple to query
Enforces unique keys, but your data won't have two columns with the same name anyway
I would assume mongoDB would generate better query plans because the structure is a lot more simple (haven't tested)
Pros of second example:
Allows multiple entries with the same key/field, but I don't feel that is useful in your case
A single index on the array can be used for all of its entries regardless of their field name
I don't think that the situation in the other example here and yours are the same. In the other example, they're creating a list of items with one of two answers, which would be more appropriately in an array, and the goal is to return a list of subdocuments that match the criteria. In your example, you're really just describing an object since they all hold different types of information, and you won't need to retrieve searchable bits of the subdocuments.

MongoDB - Query embbeded documents

I've a collection named Events. Each Eventdocument have a collection of Participants as embbeded documents.
Now is my question.. is there a way to query an Event and get all Participants thats ex. Age > 18?
When you query a collection in MongoDB, by default it returns the entire document which matches the query. You could slice it and retrieve a single subdocument if you want.
If all you want is the Participants who are older than 18, it would probably be best to do one of two things:
Store them in a subdocument inside of the event document called "Over18" or something. Insert them into that document (and possibly the other if you want) and then when you query the collection, you can instruct the database to only return the "Over18" subdocument. The downside to this is that you store your participants in two different subdocuments and you will have to figure out their age before inserting. This may or may not be feasible depending on your application. If you need to be able to check on arbitrary ages (i.e. sometimes its 18 but sometimes its 21 or 25, etc) then this will not work.
Query the collection and retreive the Participants subdocument and then filter it in your application code. Despite what some people may believe, this isnt terrible because you dont want your database to be doing too much work all the time. Offloading the computations to your application could actually benefit your database because it now can spend more time querying and less time filtering. It leads to better scalability in the long run.
Short answer: no. I tried to do the same a couple of months back, but mongoDB does not support it (at least in version <= 1.8). The same question has been asked in their Google Group for sure. You can either store the participants as a separate collection or get the whole documents and then filter them on the client. Far from ideal, I know. I'm still trying to figure out the best way around this limitation.
For future reference: This will be possible in MongoDB 2.2 using the new aggregation framework, by aggregating like this:
db.events.aggregate(
{ $unwind: '$participants' },
{ $match: {'age': {$gte: 18}}},
{ $project: {participants: 1}
)
This will return a list of n documents where n is the number of participants > 18 where each entry looks like this (note that the "participants" array field now holds a single entry instead):
{
_id: objectIdOfTheEvent,
participants: { firstName: 'only one', lastName: 'participant'}
}
It could probably even be flattened on the server to return a list of participants. See the officcial documentation for more information.