How does unordered insertion behave in db.collections.insert() in mongodb - mongodb

db.products.insert(
[
{ _id: 20, item: "lamp", qty: 50, type: "desk" },
{ _id: 21, item: "lamp", qty: twenty, type: "floor" },
{ _id: 22, item: "bulk", qty: 100 }
],
{ ordered: false }
)
I am trying to insert three documents in the collection products, but the second document has an error, the qty field has erroneous value. I am using ordered: false so I am expecting that all the other documents should get inserted except the second one, but this is not the case, none of the documents get inserted.
Then what is the difference between ordered and unordered insertion? How can I achieve the desired results in this case.

Ordered/unordered inserts are distinguished on the server side.
If you don't have the twenty variable defined, the error happens on the client side and no insert is attempted at all.

Related

Mongodb: Get last item from array in document

I have a collection in MongoDB with elements looking like this
{
userId: 'X',
access: [
{ deviceId: 'a', time: "A timestamp" },
{ deviceId: 'b', time: "Another timestamp" },
]
}
I want to match documents based on userId and then I want to get the last element in the access array. The value I am most interested in here for user with id "X" is "Another timestamp".
I do not want mongodb to return the entire document, just that last element and always the last one.
How can I write a query/aggregation that solves this?
Try using $slice:
db.collection.find({ userId: 'value' }, { access: { $slice: -1 } } )

mongodb: add an attribute to a subdocument

Given a collection of Users:
db.users.insertMany(
[
{
_id: 1,
name: "sue",
points: [
{ points: 85, bonus: 20 },
{ points: 85, bonus: 10 }
]
},
{
_id: 2,
name: "bob",
points: [
{ points: 85, bonus: 20 },
{ points: 64, bonus: 12 }
]
}]);
How do I add an attribute bonus_raw in every points, with a copy of the value of bonus value? I tried:
db.getCollection('users').update({ },
{$set:{ 'points.$.bonus_raw' : 'points.$.bonus' }}, false, true)
but I get:
The positional operator did not find the match needed from the query. Unexpanded update: points.$.bonus_raw
Updating multiple items in an array is not possible as of now in MongoDB.
To get this done, you will have to query the document, loop over all of your nested documents, and then save it back to MongoDB.
In your case, this can help:-
db.users.find({points: { $exists: true } }).forEach(function (doc){
doc.points.forEach(function (points) {
points.bonus_raw = points.bonus;
});
db.users.save(doc)
});
Also, take care of race conditions while doing an update in this way. See this

Aggregate query with no $match

I have a collection in which unique documents from a different collection can appear over and over again (in example below item), depending on how much a user shares them. I want to create an aggregate query which finds the most shared documents. There is no $match necessary because I'm not matching a certain criteria, I'm just querying the most shared. Right now I have:
db.stories.aggregate(
{
$group: {
_id:'item.id',
'item': {
$first: '$item'
},
'total': {
$sum: 1
}
}
}
);
However this only returns 1 result. It occurs to me I might just need to do a simple find query, but I want the results aggregated, so that each result has the item and total is how many times it's appeared in the collection.
Example of a document in the stories collection:
{
_id: ObjectId('...'),
user: {
id: ObjectId('...'),
propertyA: ...,
propertyB: ...,
etc
},
item: {
id: ObjectId('...'),
propertyA: ...,
propertyB: ...,
etc
}
}
users and items each have their own collections as well.
Change the line
_id:'item.id'
to
_id:'$item.id'
Currently you group by the constant 'item.id' and therefore you only get one document as result.

In MongoDB, is it possible to use $set or $mul but specify another field in the same document rather than a constant?

Say that I have a document:
{ _id: 1, item: "ABC", supplier: "XYZ", price: 10, available: 23 }
and then I run something like
db.products.update(
{ _id: 1, supplier: "XYZ" },
{ stock_value: {$mul: ["price", "available", 0.8] }}
)
to get a document
{ _id: 1, item: "ABC", supplier: "XYZ", price: 10, available: 23, stock_value: 184 }
I'd like to do this without loading everything into the client. And I need to be able to specify a different constant (e.g. the 0.8) for each supplier.
I'm thinking I should just use an aggregation with an $out to the same collection, to overwrite the whole then when the update is done, but I can't do a different aggregate() call for each supplier since I'm overwriting the collection - all other suppliers will be skipped. Is there some sort of "in place" aggregation? or a way to append $out ?

MongoDB: Upsert document in array field

Suppose, I have the following database:
{
_id: 1,
name: 'Alice',
courses: [
{
_id: 'DB103',
credits: 6
},
{
_id: 'ML203',
credits: 4
}
]
},
{
_id: 2,
name: 'Bob',
courses: []
}
I now want to 'upsert' the document with the course id 'DB103' in both documents. Although the _id field should remain the same, the credits field value should change (i.e. to 4). In the first document, the respective field should be changed, in the second one, {_id: 'DB103', credits: 4} should be inserted into the courses array.
Is there any possibility in MongoDB to handle both cases?
Sure, I could search with $elemMatch in courses for 'DB103' and if I haven't found it, insert, otherwise update the value. But these are two steps and I would like to do both in just one.