I'm searching for documents that contain a particular _id in the contacts array in the document. So here's the structure:
{
"_id": ObjectId("505c2daea9d397f2260001cd"),
"contacts": [
{
"userGroupId": ObjectId("50422b53743d6c7c0e000000"),
"userId": ObjectId("5061f8c66096eee07d000008")
},
{
"userGroupId": ObjectId("505bf9476096ee990200000e"),
"userId": ObjectId("505c2daea9d397f2260001ce")
},
{
"userGroupId": ObjectId("50422b75743d6c700e000004"),
"userId": ObjectId("506cff736096ee1e26000384")
},
{
"userGroupId": ObjectId("50422b66743d6c6b0e000000"),
"userId": ObjectId("505c2daea9d397f2260001cf")
},
{
"userGroupId": ObjectId("5050e86aa9d3977b67000000"),
"userId": ObjectId("506494ef6096ee021f000064")
},
{
"userGroupId": ObjectId("50422b53743d6c7c0e000000"),
"userId": ObjectId("504d72246096ee2348000008")
},
{
"userId": ObjectId("50735e8e6096ee7c510002b9"),
"userGroupId": ObjectId("5046c73e6096ee1b77000001")
}
]
}
Here's a second document:
{
"_id": ObjectId("505c2da0a9d397f2260000b7"),
"contacts": [
{
"userGroupId": ObjectId("50422b66743d6c6b0e000000"),
"userId": ObjectId("505c2da0a9d397f2260000b8")
},
{
"userId": ObjectId("5061f8c66096eee07d000008"),
"userGroupId": ObjectId("50422b53743d6c7c0e000000")
},
{
"userId": ObjectId("50735e8e6096ee7c510002b9"),
"userGroupId": ObjectId("5046c73e6096ee1b77000001")
}
]
}
You'll notice that both documents have a userId of ObjectId("50735e8e6096ee7c510002b9") in them. I run this command:
db.collection.find({ 'contacts':
{$elemMatch: { userId: ObjectId("50735e8e6096ee7c510002b9") } }
});
Which should (I think) return both documents. But it only returns the second document. Not the first. I have also tried:
db.collection.find({'contacts.userId': ObjectId("50735e8e6096ee7c510002b9") });
which does the same thing as the $elemMatch query.
I'm probably missing something really elementary, but if you guys could offer some advice I'd really appreciate it.
This was a problem with the application layer it turns out, not Mongo. One of the records was numerically keyed, the other was not, I just had been working with Rock Mongo which seems to key all the arrays.
Thanks for your help JohnnyHK
Related
In the database, I have documents like the following
Ticket {
"eventHistory": [
{
"event": "CREATED",
"timestamp": "aa-bb-cccc"
},
{
"event": "ASSIGNED",
"timestamp": "ii-jj-kkkk"
},
...
{
"event": "CLOSED",
"timestamp": "xx-yy-zzzz"
}
]
}
I would like to add a closedAt field to the relevant Tickets, getting the value from the eventHistory array's last element. The resultant document would look like the following
Ticket {
"eventHistory": [
{
"event": "CREATED",
"timestamp": "aa-bb-cccc"
},
{
"event": "ASSIGNED",
"timestamp": "ii-jj-kkkk"
},
...
{
"event": "CLOSED",
"timestamp": "xx-yy-zzzz"
}
],
"closedAt": "xx-yy-zzzz"
}
The following pipeline allows me to use the entire object that's present as the eventHistory array's last element.
db.collection.updateMany(
<query>,
[
"$set": {
"closedAt": {
"$arrayElemAt": [
"$eventHistory",
-1
]
}
}
]
...
)
But I want to use only the timestamp field; not the entire object.
Please help me adjust (and/or improve) the pipeline.
One option to fix your query is:
db.collection.updateMany(
<query>,
[
{
$set: {
"Ticket.closedAt": {
$last: "$Ticket.eventHistory.timestamp"
}
}
}
])
See how it works on the playground example
But note that you assume that last item is a closing one. Is this necessarily the case? Otherwise you can validate it.
I am working on a Node.js application that is using a MongoDB database with Mongoose. I've been stuck in this thing and didn't come up with the right query.
Problem:
There is a collection named chats which contain embedded documents (rooms) as an array of objects. I want to delete these embedded documents (rooms) through Ids which are in the array.
{
"_id": "ObjectId(6138e2b55c175846ec1e38c5)",
"type": "bot",
"rooms": [
{
"_id": "ObjectId(6138e2b55c145846ec1e38c5)",
"genre": "action"
},
{
"_id": "ObjectId(6138e2b545c145846ec1e38c5)",
"genre": "adventure"
}
]
},
{
"_id": "ObjectId(6138e2b55c1765846ec1e38c5)",
"type": "person",
"rooms": [
{
"_id": "ObjectId(6138e2565c145846ec1e38c5)",
"genre": "food"
},
{
"_id": "ObjectId(6138e2b5645c145846ec1e38c5)",
"genre": "sport"
}
]
},
{
"_id": "ObjectId(6138e2b55c1765846ec1e38c5)",
"type": "duo",
"rooms": [
{
"_id": "ObjectId(6138e21c145846ec1e38c5)",
"genre": "travel"
},
{
"_id": "ObjectId(6138e35645c145846ec1e38c5)",
"genre": "news"
}
]
}
I am converting my array of ids into MongoDB ObjectId so I can use these ids as match criteria.
const idsRoom = [
'6138e21c145846ec1e38c5',
'6138e2565c145846ec1e38c5',
'6138e2b545c145846ec1e38c5',
];
const objectIdArray = idsRoom.map((s) => mongoose.Types.ObjectId(s));
and using this query for the chat collection. But it is deleting the whole document and I only want to delete the rooms embedded document because the ids array is only for the embedded documents.
Chat.deleteMany({ 'rooms._id': objectIdArray }, function (err) {
console.log('Delete successfully')
})
I really appreciate your help on this issue.
You have to use $pull operator in a update query like this:
This query look for documents where exists the _id into rooms array and use $pull to remove the object from the array.
yourModel.updateMany({
"rooms._id": {
"$in": [
"6138e21c145846ec1e38c5",
"6138e2565c145846ec1e38c5",
"6138e2b545c145846ec1e38c5"
]
}
},
{
"$pull": {
"rooms": {
"_id": {
"$in": [
"6138e21c145846ec1e38c5",
"6138e2565c145846ec1e38c5",
"6138e2b545c145846ec1e38c5"
]
}
}
}
})
Example here.
Also you can run your query without the query parameter (in update queries the first object is the query) like this and result is the same. But is better to indicate mongo the documents using this first object.
I have a recursive structure in one of my MongoDB collections, like so:
{
"id": String,
"date": Date,
"text": String
"replies": [{
// Same structure as above
}]
}
I need to update a document in this hierarchy by adding in a reply to a nested document. The guarantees are as follows:
The object to reply to is guaranteed to exist.
The path to the object to which a reply is to be posted is known (i.e., we have a sequence of the _id attributes to navigate).
The recursion depth is not bounded.
Searching SO gives me the following relevant questions:
Querying, 2013 - The recommendation was to switch to a graph DB.
Updating, 2015 - The recommendation was to use the $[] operator.
Based on the latter, my attempt was:
await commCollection.update(
{ _id: topLevel['_id'] },
{
$push: {
'replies.$[].$[comment_arr].replies': {
id: commentId,
text: comment,
date,
replies: []
}
}
},
{ arrayFilters: [{ 'comment_arr.id': responseTo }]}
);
where topLevel is the root document, responseTo is the id attribute of the object to add the reply to. This however, does not seem to work. What am I doing wrong, and how do I achieve this?
Update: An example below. Here's an example of a document from MongoDB Atlas:
{
"_id": {
"$oid": "605fdb8d933c5f50b4d2225e"
},
"id": "mr9pwc",
"username": "recrimination-logistical",
"upvotes": {
"$numberInt": "0"
},
"downvotes": {
"$numberInt": "0"
},
"text": "Top-level comment",
"date": {
"$date": {
"$numberLong": "1616894861300"
}
},
"replies": [{
"id": "dflu1h",
"username": "patrolman-hurt",
"upvotes": {
"$numberInt": "0"
},
"downvotes": {
"$numberInt": "0"
},
"text": "Testing reply level 1!",
"date": {
"$date": {
"$numberLong": "1618387567042"
}
},
"replies": [] // ----> want to add a reply here
}]
}
I've indicated where we want a reply added. responseTo in this case would be dflu1h.
Just need to remove $[] positional
Field name in arrayFilters must be an alphanumeric string beginning with a lowercase letter, Change comment_arr to any alphabets only like commentArr, remove special characters
await commCollection.update(
{ _id: topLevel['_id'] },
{
$push: {
"replies.$[commentArr].replies": {
id: commentId,
text: comment,
date,
replies: []
}
}
},
{ arrayFilters: [{ "commentArr.id": responseTo }] }
)
Playground
I'm having an issue updating a nested Array in a document. Reading around the topic i've come across various method, one that i've tweaked below, however nothing seems to work for me!
I'm trying to update the field systemUpdate_DT which is in a parent Array called List and a child array called customData. I'm referring to the object in the child array using the key _id of the parent array and key field_id in the child array.
How do I update the systemUpdate_DT of the respective object?
Live Example: https://mongoplayground.net/p/453OFPOQqBp
A document in the collection looks like:
[
{
"_id": "6032a5ad80443334a35f2232",
"List": [
{
"_id": "6032a5af80443334a35f2234",
"customData": [
{
"_id": "6032a5bc80443334a35f223c",
"systemUpdate_DT": null,
"field_id": "6032a5bc80443334a35f223b"
},
{
"_id": "6032a5c280443334a35f223e",
"systemUpdate_DT": null,
"field_id": "6032a5c280443334a35f223d"
}
]
},
{
"_id": "6032a5b080443334a35f2236",
"customData": [
{
"_id": "6032a5bc80443334a35f223c",
"systemUpdate_DT": null,
"field_id": "6032a5bc80443334a35f223b"
},
{
"_id": "6032a5c280443334a35f223e",
"systemUpdate_DT": null,
"field_id": "6032a5c280443334a35f223d"
}
]
}
]
}
]
My Update Query looks like:
db.collection.updateOne({
{
"List._id": mongodb.ObjectId("6032a5af80443334a35f2234"),
"List.customData.field_id": mongodb.ObjectId("6032a5bc80443334a35f223b")
},
{
$set: {
"List.$.customData.systemUpdate_DT": 'updatedDTTM'
}
})
As there's two nested arrays in your document, you can't set the field with classic positional operator '$'.
Instead, you should use the arrayFilters option like this:
db.collection.update({
"_id": ObjectId("6032a5ad80443334a35f2232")
},
{
$set: {
"List.$[list].customData.$[customData].systemUpdate_DT": "updatedDTTM"
}
},
{
"multi": false,
"upsert": false,
arrayFilters: [
{
"list._id": {
"$eq": ObjectId("6032a5af80443334a35f2234")
}
},
{
"customData._id": {
"$eq": ObjectId("6032a5bc80443334a35f223c")
}
}
]
})
try it online: mongoplayground.net/p/fb_86rNUKvt
I collected followers list and friends list for n number of users from twitter and stored them in mongodb.
Here is a sample document:
{
"_id": ObjectId("561d6f8986a0ea57e51ec95c"),
"status": "True",
"UserId": "1489245878",
"followers": [
"1566382441",
"1155774331"
],
"followersCount": 2,
"friendsCount": 5,
"friends": [
"1135511478",
"998082481",
"565321118",
"848123988",
"343334562"
]
}
I wanted to know within my collection, are there any userids that are also in the followers list of some other documents. Lets say we have user "a", now i would like to know if user "a" is in the followers list of any other document within the same collection. I'm not sure how to do this. In case if we have, i would like to project the userid and the _id of the document that has the userid within the followers list.
I guess you can use aggregate function like below to get this result.
db.getCollection('your_collection").aggregate([
{
"$match": {
"followers": "1566382441"
}
},
{
"$project": {
"followers": 1
}
},
{
"$unwind": "$followers"
},
{
"$match": {
"followers": "1566382441"
}
},
{
"$group": {
"_id": "$followers",
"ids": {
"$addToSet": "$_id"
}
}
},
{
"$project": {
"userId": "$_id",
"ids": 1,
"_id": 0
}
}
])
I am using only a sample of your data. You can add your list of users for whom you are trying to filter in both stages of "$match". Just see if this helps.
P.S: I know its been a long time since you asked this question! But you know, its never late!