Why does this push not add a new field? (mongoDB) - arrays

I have a collection of restaurants where each document includes data such as the name, location, reviews, etc, and I'm attempting to push data which includes two reviews to the restaurant located in the borough of Brooklyn. This document happens to not currently have an array field of "reviews". According to everything I've looked at, the $push function should automatically add the array to the document, but it does not. Here is the code:
db.restaurants.updateOne(
{ borough: 'Brooklyn' },
{
$push: {
reviews: {
$each: [
{
name: 'Frank Zappa',
date: 'January 3, 2019',
rating: 3,
comments: 'This restaurant is not good',
},
{
name: 'Freddie Mercury',
date: 'January 3, 2019',
rating: 5,
comments: 'This restaurant is my favorite',
},
],
},
},
}
);
The next command after this is to push the same reviews to another restaurant that does already have the array field "reviews", and also slice to 2. The only difference in code between these two is the filter and the slice modifier. The second works perfectly, the first does not.
Am I misunderstanding how push should work? Using push is a requirement in this case, though I did also try addToSet with the same

https://mongoplayground.net/p/MxH01R4dxjU
it seems your Query is working fine plz check that you provided right values in the filter operation

Turns out I didn't pay close enough attention to how many documents have the "borough" : "Brooklyn" field and there was more than one. Changed to updateMany and the problem was solved. Thanks for the time and attention!

Related

How to properly design a database, a single object vs multiple with relations

I am working on a project that will rely kinda heavily on a database, I've done several projects by now, but most of them barely had any significant database need, that would require me to put significant thought in it, but that time has come. I don't know much about databases, and I am not looking for someone to do it instead of me, but I am just looking for pointers and what to study/read in order to figure out how to handle the situation.
What the app will do is keep track of the items in stock (in the inventory) in a company, related to the products that it manufactures. I will have to be able to pull various kind of information, wether its all invoices, or all invoices related to a given product, or all items related to a given product, or all items for all products, and so on, you get the idea.
The basic structure that I have for now looks like this:
const inventory = {
products: [
{
title: "",
production: {
finalized: 0,
inProduction: 0,
},
items: [
{
title: "",
price: {
per: 0,
total: 0,
},
quantity: {
current: 0,
type: "",
},
operations: {
added: [
{
date: new Date(),
quantity: 0,
invoice: {
number: "",
supplier: "",
},
},
],
removed: [
{
date: new Date(),
quantity: 0,
expenseId: "",
},
],
},
},
],
},
],
};
It is not complex at all, an array of products, and information about these products. Quantities, when a new quantity was added, when a quantity was taken, and so on.
The question is, do I make this with just 1 model for the whole inventory, which I am guessing will work, but will probably not be optimal.
Another approach that comes to mind is to make models for the items, invoices, products and so on, and then just have some logic that relates all of that within the inventory to get the structure that I have above. That performance wise will probably be better, because if I want to pull all invoices, I will just have to pull the invoices model instead of the whole inventory and loop through it to find my invoices.
What other options do I have?
I forgot to add that I will be using Mongoose, Express, React and Node.

Updating firestore array of maps shows error : Unsupported field value: undefined

i have a document in firestore like below
what i want to do is update this fields time and stage
i tried these with update and set methods
db.collection("record").doc("user"+user).collection("datas").doc("roadmap").update({
first:[{
0:[ stage:"new stage",
time:"new time,
done:false
}]
}]
})
and
db.collection("startups").doc("user"+user).collection("datas").doc("roadmap").update({
first:{[
stage:"new stage",
time:"new time",
done:false
}]
})
but it always shows error such as :[![FirebaseError: Function DocumentReference.set() called with invalid data. Unsupported field value: undefined]
The following should do the trick:
db.collection("record").doc("user"+user).collection("datas").doc("roadmap")
.update({ first: [{ stage: 'new stage', time: 'new time', done: false }] });
This will work because your array has only one element (a map).
Note that if you want to modify one specific element of an array with several elements, you will need to first read the array in your front-end, modify the array and then write back the modified array to Firestore.
Even if it is not what you are looking for, it's worth noting the arrayUnion() and arrayRemove() methods, see here for more details.

Mongodb Aggregating information into new collection automatically?

I'm trying to figure out the best way to implement this.
If I have one large collection in my mongodb that holds all of my "Inventory" information for my warehouse without regard to the specific "type" of inventory, what is the best way to aggregate the data into their own collections continuously? **Added this information after-the-fact: I'm using a Mean stack so maybe some of this is better to just do server-side with an angular function rather than actually keeping a collection updated?
For instance, my current "Inventory" collection would have items such as
_id: something, name: item1, type: chemical, vendor: something, safetycode: ####, machineUse: n/a, equipmentUse: n/a ...
_id: something2, name: item2, type: machine, vendor: something2 safetycode: n/a, machineUse: "digging", equipmentUse: n/a ...
_id: something3, name: item3, type: equipment, vendor: something3 safetycode: n/a, machineUse: n/a, equipmentUse: "Computer" ...
I'm inclined to $group but is this best practice to keep a 'SEPERATE' collection updated with their respective groups? You'll notice in the following that the aggregate function should collect the specific 'type'(Chemical, Machine, equipment, etc...) and store all the details of each item collected with fields that are only used for that 'type' (i.e, Chemicals use 'safetycode', machines DO NOT use saftey code so it's left out and instead 'machineUse' is stored, etc.)
db.invfulls.aggregate([
{ "$group": {
"_id": "$itype",
"total": {$sum : 1},
"items":{
"$push":{
"$cond":{
"if": {"$eq":["$itype","Chemical"]},
"then": {"id":"$_id", "name":"$name", "vendor":"$vendor", "review":"$needsreview"},
"else": {"id":"$_id", "name":"$name", "vendor":"$vendor"}
}
}
}
}},
{$out: "invByType"}
])
Additionally, would I have to make this a function in the database and call that function anytime there is a new "post" made?
I've read a bit about the mapReduce as well but everything I read says it's a very slow and shouldn't be used?

MongoDB: Remove all array entries except the last X entries

Node.JS MongoDB Driver is used.
The database entries look like that:
{
_id: ObjectId("224444202654a21928801814"),
category: "Test",
entries: [
{
_id: ObjectId("324444202dd4a21328802214"),
username: "Tester",
},
{
_id: ObjectId("324444232dd4a21328802215"),
username: "Tester2",
}
[many more...]
]
}
There are thousands of objects in the entries array.
The last array entries are the newest ones.
Now all objects should be deleted inside the entries array except the last 50 entries.
Is there a possibility to achieve that with one update/remove call? Maybe with the $slice operator?
It's not possible to achieve what you want with the $slice operator. I think using the javascript slice operator within cursor forEach() is your best bet. Try this out:
db.foo.find({}).forEach( function(doc) {
db.foo.update(
{_id:doc._id},
{$set:{entries:doc.entries.slice(doc.entries.length - 50)}}
)
})
Note: The above command would run fine in the Mongo Shell.

MongoDB: Query and retrieve objects inside embedded array?

Let's say I have the following document schema in a collection called 'users':
{
name: 'John',
items: [ {}, {}, {}, ... ]
}
The 'items' array contains objects in the following format:
{
item_id: "1234",
name: "some item"
}
Each user can have multiple items embedded in the 'items' array.
Now, I want to be able to fetch an item by an item_id for a given user.
For example, I want to get the item with id "1234" that belong to the user with name "John".
Can I do this with mongoDB? I'd like to utilize its powerful array indexing, but I'm not sure if you can run queries on embedded arrays and return objects from the array instead of the document that contains it.
I know I can fetch users that have a certain item using {users.items.item_id: "1234"}. But I want to fetch the actual item from the array, not the user.
Alternatively, is there maybe a better way to organize this data so that I can easily get what I want? I'm still fairly new to mongodb.
Thanks for any help or advice you can provide.
The question is old, but the response has changed since the time. With MongoDB >= 2.2, you can do :
db.users.find( { name: "John"}, { items: { $elemMatch: { item_id: "1234" } } })
You will have :
{
name: "John",
items:
[
{
item_id: "1234",
name: "some item"
}
]
}
See Documentation of $elemMatch
There are a couple of things to note about this:
1) I find that the hardest thing for folks learning MongoDB is UN-learning the relational thinking that they're used to. Your data model looks to be the right one.
2) Normally, what you do with MongoDB is return the entire document into the client program, and then search for the portion of the document that you want on the client side using your client programming language.
In your example, you'd fetch the entire 'user' document and then iterate through the 'items[]' array on the client side.
3) If you want to return just the 'items[]' array, you can do so by using the 'Field Selection' syntax. See http://www.mongodb.org/display/DOCS/Querying#Querying-FieldSelection for details. Unfortunately, it will return the entire 'items[]' array, and not just one element of the array.
4) There is an existing Jira ticket to add this functionality: it is https://jira.mongodb.org/browse/SERVER-828 SERVER-828. It looks like it's been added to the latest 2.1 (development) branch: that means it will be available for production use when release 2.2 ships.
If this is an embedded array, then you can't retrieve its elements directly. The retrieved document will have form of a user (root document), although not all fields may be filled (depending on your query).
If you want to retrieve just that element, then you have to store it as a separate document in a separate collection. It will have one additional field, user_id (can be part of _id). Then it's trivial to do what you want.
A sample document might look like this:
{
_id: {user_id: ObjectId, item_id: "1234"},
name: "some item"
}
Note that this structure ensures uniqueness of item_id per user (I'm not sure you want this or not).

Resources