Combine two similar documents MongoDB - 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"
}
])

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

MongoDB querying aggregation in one single document

I have a short but important question. I am new to MongoDB and querying.
My database looks like the following: I only have one document stored in my database (sorry for blurring).
The document consists of different fields:
two are blurred and not important
datum -> date
instance -> Array with an Embedded Document Object; Our instance has an id, two not important fields and a code.
Now I want to query how many times an object in my instance array has the group "a" and a text "sample"?
Is this even possible?
I only found methods to count how many documents have something...
I am using Mongo Compass, but i can also use Pymongo, Mongoengine or every other different tool for querying the mongodb.
Thank you in advance and if you have more questions please leave a comment!
You can try this
db.collection.aggregate([
{
$unwind: "$instance"
},
{
$unwind: "$instance.label"
},
{
$match: {
"instance.label.group": "a",
"instance.label.text": "sample",
}
},
{
$group: {
_id: {
group: "$instance.label.group",
text: "$instance.label.text"
},
count: {
$sum: 1
}
}
}
])

How to update/insert into a mongodb collection with the result of aggregate query on the another collection

I have a below aggregate query and I wanted to insert/update this result into another collection.
db.coll1.aggregate([
{
$group:
{
_id: "$collId",
name: {$first:"$name"} ,
type: {$first:"$Type"} ,
startDate: {$first:"$startDate"} ,
endDate: {$first:"$endDate"}
}
}
])
I have another collection coll2, which has fields in the above query and some additional fields too.
I may already have the document created in Coll2 matching the _id:collId in the above query. If this Id matches, I want to update the document with the field values of the result and keep the values of other fields in the document.
If the Id does not exists, it should just create a new document in Coll2.
Is there a way to do it in the MongoDB query. I want to implement this in my Spring application.
We can use $merge to do that. It's supported from Mongo v4.2
db.collection.aggregate([
{
$group:{
"_id":"$collId",
"name": {
$first:"$name"
},
"type":{
$first:"$Type"
},
"startDate":{
$first:"$startDate"
},
"endDate":{
$first:"$endDate"
}
}
},
{
$merge:{
"into":"collection2",
"on":"_id",
"whenMatched":"replace",
"whenNotMatched":"insert"
}
}
])

MongoDB: update nested value in a collection based on existing field value

I want to update nested _ids over an entire collection IF they are of a type string.
If I have object that look like this...
user : {
_id: ObjectId('234wer234wer234wer'),
occupation: 'Reader',
books_read: [
{
title: "Best book ever",
_id: "123qwe234wer345ert456rty"
},
{
title: "Worst book ever",
_id: "223qwe234wer345ert456rty"
},
{
title: "A Tail of Two Cities",
_id: ObjectId("323qwe234wer345ert456rty")
}
]
}
and I want to change the type of the _Ids from string to ObjectId
how would I do that.??
I have done "this" in the past...But this is working on NON-nested item - I need to change a nested value
db.getCollection('users')
.find({
$or: [
{occupation:{$exists:false}},
{occupation:{$eq:null}}
]
})
.forEach(function (record) {
record.occupation = 'Reader';
db.users.save(record);
});
Any help - I am trying to avoid writing a series of loop on the app server to make db calls - so I am hoping for something directly in 'mongo'
There isn't a way of doing (non $rename) updates operations on a document while referencing existing fields -- MongoDB: Updating documents using data from the same document
So, you'll need to write a script (similar to the one you posted with find & each) to recreate those documents with the correct _id type. To find the subdocuments to update you can use the $type operator. A query like db.coll.find({nestedField._id: {$type: 'string' }}) should find all the full documents that have bad subdocuments, or you could do an aggregation query with $match & $unwind to only get the subdocuments
db.coll.aggregate([
{ $match: {'nestedField._id': {$type: 'string' }}}, // limiting to documents that have any bad subdocuments
{ $unwind: '$nestedField'}, // creating a separate document in the pipeline for each entry in the array
{ $match: {'nestedField._id': {$type: 'string' }}}, // limiting to only the subdocuments that have bad fields
{ $project: { nestedId: 'nestedField._id' }} // output will be: {_id: documentedId, nestedId }
])
I am trying to avoid writing a series of loop on the app server to make db calls - so I am hoping for something directly in 'mongo'
You can run js code directly on the mongo to avoid making api calls, but I don't think there's any way to avoid looping over the documents.