MongoDB Aggregation w/ Embedded Documents - mongodb

I have a document that I want to split up into multiple documents.
The document looks like this.
{
a:1,
b:2,
c:3,
d:4,
}
{
a:5,
b:6
c:7
d:8
}
I want to pull out "d" into separate documents. I know that $unwind would unwind an array, but how would I unwind a situation like this?
Document 1
{
d:4
}
Document 2
{
d:8
}

Related

Query to delete the last three documents in a collection in mongodb

Consider my database collection is having 5 documents and I need to delete the last 3 documents. So what is the query in Mongodb
Maybe something like this:
db.collection.aggregate([
{
$sort: {
_id: 1
}
},
{
$limit: 2
},
{
$out: "collection"
}
])
Explained:
Sort collection by inserted order
FIlter only the first 2 documents.
Store back the content to the original collection replacing the original.
Playground

MongoDB: Count documents in array of nested document for a specific field in the main document

i have this collection on MongoDB
Collection structure
The main document has like main Field wineName. Now in this image the array of nested document (reviews) is only one but could be several reviews for each wines.
My question is how can I count the number of reviews that I have for each Wine?
Thank you in advance for the answer
You can use the $size aggregation operator for this:
db.collection.aggregate([
{
"$addFields": {
"reviewCount": {
$size: "$reviews"
}
}
}
])
Mongo Playground

How to query nested arrays in mongoDB to find documents with elements that don't exist

I'm trying to make an aggregation query to find all documents that do not contain a certain element. It needs to be an aggregation because I want to be able to edit the returned documents. Eg. I only want to return some fields and I also want to be able to do a group on eg. the "producer" element.
I already tried practically all I can think of. I tried unwinding the arrays, but then I created even more documents where the element packagingInformation was mission than originally. I tried using $ne, $eq, $gt, $lte,.. to find the documents needed,... but they always return all documents because of the nested array structure.
$ArrayToObject didn't do the trick either for me.
I'm clueless on how to achieve this. The tripple nested array structure beats my imagination.
The only thing that returns me the wanted result is the following query:
db.product.find({
"json.productData.productInformation.details.packagingInformation": { $exists: false }
})
But this doesn't suffice since it's not an aggregate, thus it doens't allow me to continue to do queries with the results. And the $exists doesn't work in aggregates.
This is the JSON structure which I'm struggling with (dummy data).
{
_id: 5ckflsmdk543klmf543klmtrkmgdfm,
productNumber: 001,
json: {
productData: {
productNumber: 001,
producer: coca-cola,
productInformation: [
{
trackingInformation: {
lastUpdate: 01-01-12,
creationDate: 01-01-11
},
details: [
packagingInformation: [
quantity: 5,
size: 20cm
],
productType: drinks,
otherMeaningLessInformation: whatever,
andEvenMoreInformationInArrays: [
andTheInformationGoesOn: wow,
andOn: nastyArrayStructures
]
]
]
}
}
}
}
The wanted result would be to return all the documents that do not contain the packagingInformation array or the packagingInformation.quantity element.
or even better, to return all documents but with an extra field:
containsPackagingInformation: true/false. With false being the result of all documents that do not contain packagingInformation or packagingInformation.quantity.
$exists DOES WORK in a aggregation.
$exists works the same way it works in .find
you can form a query like:
db.collection.aggregate({ $match: {
$or: [
{
"json.productData.productInformation.details.packagingInformation.quantity": {
$exists: false
}
},
{
"json.productData.productInformation.details.packagingInformation": {
$exists: false
}
}
] } })
Try this query here with dummy data

Query mongodb array of documents

I've a bunch of documents that look like:
{
"ids": [{"name":"aa", "age":1}, {"name":"bb", "age":2}]
}
I'd like to be able to query my documents providing a collection of ids, something like
db.getCollection('Collection').find({"ids":{$in : [{"name":"aa", "age":1}, {"name":"bb", "age":2}]}})
Generally that works, however it breaks when the fields order is changed, so for example I cannot find documents when I execute the following query
db.getCollection('Collection').find({"ids":{$in : [{"age":1,"name":"aa"}, { "age":2, "name":"bb"}]}})
I know that I could try to always execute a query with fields "in order", but from my current task perspective it's not always possible. Any help with that ?
You need $elemMatch when you want to run your query against an array of objects:
db.col.find({ $or: [ { "ids": { $elemMatch: {"age":1,"name":"aa"} } }, { "ids": { $elemMatch: { "age":2, "name":"bb"} } } ] })
Mongo Playground
EDIT: you can decide whether $or or $and should be a top level operator (depending on your use case)

Combine two similar documents MongoDB

Is there any possible way to combine two documents in mongodb?
Imagine I have a collection with this documents:
{ "_id":ObjectId("142342432"), "name":"Chris", "surname":"Patrick", "pets":["dog", "cat"] }
{ "_id":ObjectId("142342752"), "name":"Chris", "surname":"Patrick", "pets":["lizard"] }
more than x2000 documents
And some other documentes. My idea would be to group each of the entries by name and surname and in case they match, join the pets array $addToSet.
The idea is to delete those two documents and add a new one with a new generated id and the combination. Deleting one document and appending the array to the other one, would also be ok.
My main problem is that I should be updating the collection, so it wouldn't be just a dump. And it can't be inefficient to dump it into a file and import it later on.
Thanks!
Update: Using mongodb 3.4
you can achieve this in a single query :
first, unwind pets array
then, group by name and surname, and combine arrays with $addToSet
finally, write the output to the same collection using $out
Be carefull, this will overwrite the original collection!
before running this, you should create a dump of your current collection to avoid any data loss
here is the query:
db.collectionName.aggregate([
{ $unwind: {
path: "$pets",
preserveNullAndEmptyArrays: true
}
},
{
$group:{
_id:{
name:"$name",
surname:"$surname"
},
pets:{
$addToSet:"$pets"
},
otherField: {
$first: "$otherField"
}
}
},
{
$out:"collectionName"
}
])