How to pull nested document from the array of documents in mongodb? - javascript

I am trying to remove a nested objects array in my document. The scenario is that i am searching for the days an event will be organised for, by using its eventid
const { eventid, typesOfTicketId } = req.params;
const eventDays = await EventDate.find({event: eventid});
Here eventid is passed from params as "5e9c0f0593ab3c058e282bfa". I then want to remove a requested day from the nested objects array. From the above query, I am receiving an array of dates and on each index of array the document is in this format:
[{
"_id" : ObjectId("5ea7f54b8b22480431f1a455"),
"day" : "1588186800",
"typesOfTicket" : [
{
"_id" : ObjectId("5ea7f54b8b22480431f1a456"),
"ticket" : "Adult Tickets",
"noTickets" : 40,
"price" : 50,
"ticketsLeft" : 40
},
{
"_id" : ObjectId("5ea7f54b8b22480431f1a457"),
"ticket" : "Children Tickets",
"noTickets" : 50,
"price" : 30,
"ticketsLeft" : 50
}
],
"event" : ObjectId("5e9c0f0593ab3c058e282bfa"),
"__v" : 0
},
{
"_id" : ObjectId("5ea7f5678b22480431f1a45f"),
"day" : "1588273200",
"typesOfTicket" : [
{
"_id" : ObjectId("5ea7f5678b22480431f1a460"),
"ticket" : "Male Tickets",
"noTickets" : 50,
"price" : 5,
"ticketsLeft" : 50
},
{
"_id" : ObjectId("5ea7f5678b22480431f1a461"),
"ticket" : "Female Tickets",
"noTickets" : 50,
"price" : 5,
"ticketsLeft" : 50
}
],
"event" : ObjectId("5e9c0f0593ab3c058e282bfa"),
"__v" : 0
}]
What i want is to find a way to remove the document in the nested typesOfTicket array, like lets say i want to remove the Object with id: typesOfTicketId. (e.g typesOfTicketId = "5ea7f5678b22480431f1a461"), the female ticket one by passing its ID.
I have already tried this query:
await EventDate.update({event: eventid}, {
$pull: {
typesOfTicket: {
_id: "typesOfTicketIDHERE"
}
}
});
But the above given query is only working if i am removing the first index of eventDays Array, like if i am deleting the ID: "5ea7f54b8b22480431f1a456", then this will work but if i am going for the id's on the second index like "Female tickets"/"5ea7f5678b22480431f1a461", then it is not working.

I found the solution to my problem, the above query did work correctly after just some adjustments
await EventDate.update({event: eventid}, {
$pull: {
typesOfTicket: {
_id: "typesOfTicketIDHERE"
}
}
}, { multi: true });
Just specifying the multi params to true will do the trick.

Related

Find nested property from ember lodash and pick the value

I am new to javascript.
I would like to check whether the specific nested property is present or not in an array of items, ex)
[{
"_id" : ObjectId("5c4ec057e21b840001968d31"),
"status" : "ACTIVE",
"customerId" : "sample-book",
"bookInfo" : {
"bookChunks" : [
{
"key" : "Name",
"value" : "test"
},
{
"key" : "Surname1",
"value" : "testtt"
},
{
"key" : "user-contact",
"value" : "sample-value",
"ContactList" : {
"id" : "sample-id",
"timeStamp" : "Tue, 20 Sep 2016 07:49:25 +0000",
"contacts" : [
{
"id" : "contact-id1",
"name" : "Max Muller",
"phone_number" : "+XXXXXXX"
},
{
"id" : "contact-id2",
"name" : "Max Muller",
"phone_number" : "+XXXXXXX"
}
]
}
}
]
}
},
{
"_id" : ObjectId("5c4ec057e21b840001968d32"),
"status" : "ACTIVE",
"customerId" : "sample-book1",
"bookInfo" : {
"bookChunks" : [
{
"key" : "Name",
"value" : "test"
},
{
"key" : "Surname1",
"value" : "testtt"
}
]
}
}]
Here, I would like to find whether any item has ContactList or contacts present. If it is present take the item and put it in a separate list.
I am using ember-lodash. Using normal javascript or lodash would be fine for me. Any help will be really appreciated.
You could use filter and some. This returns all the objects which have at least one object with ContactList property inside bookInfo.bookChunks array.
const input=[{"_id":"5c4ec057e21b840001968d31","status":"ACTIVE","customerId":"sample-book","bookInfo":{"bookChunks":[{"key":"Name","value":"test"},{"key":"Surname1","value":"testtt"},{"key":"user-contact","value":"sample-value","ContactList":{"id":"sample-id","timeStamp":"Tue, 20 Sep 2016 07:49:25 +0000","contacts":[{"id":"contact-id1","name":"Max Muller","phone_number":"+XXXXXXX"},{"id":"contact-id2","name":"Max Muller","phone_number":"+XXXXXXX"}]}}]}},{"_id":"5c4ec057e21b840001968d32","status":"ACTIVE","customerId":"sample-book1","bookInfo":{"bookChunks":[{"key":"Name","value":"test"},{"key":"Surname1","value":"testtt"}]}}]
const output = input.filter(o =>
o.bookInfo.bookChunks.some(c => "ContactList" in c)
)
console.log(output)
If you just want to check if any of the objects have ContactList, you could replace filter with another some
(Note: This assumes that bookInfo.bookChunks will not be undefined. Otherwise you'd have to add a undefined check before using the nested property)

Looping though all documents in the collection and an array in each document to match array value to the project

I have a MongoDB collection with the following structure:
/* 1 */
{
"_id" : ObjectId("5cdb24b41a40ae58e6d690fd"),
"versions" : [
ObjectId("5cdb24b41a40ae58e6d690fe")
],
"releases" : [],
"monetization" : [],
"owner" : "testuser",
"name" : "test-repo-2",
"repoAddress" : "/testuser/test-repo-2",
"repoKey" : null,
"__v" : 0
}
/* 2 */
{
"_id" : ObjectId("5cdb23cb1a40ae58e6d690fa"),
"versions" : [
ObjectId("5cdb23cb1a40ae58e6d690fb"),
ObjectId("5cdda9c54e6d0b795a007960")
],
"releases" : [
ObjectId("5cdda9c54e6d0b795a00795c")
],
"monetization" : [],
"owner" : "testuser",
"name" : "test-repo-1",
"repoAddress" : "/testuser/test-repo-1",
"repoKey" : null,
"__v" : 2,
"createdAt" : ISODate("2019-05-16T18:19:49.159Z"),
"updatedAt" : ISODate("2019-05-16T18:19:49.252Z")
}
I need to loop though all the documents in the collection as well as they array of versions to look for a specific to match it to the project. I need to do this with NodeJS, but for now I'm trying it from mongoshell. I'm trying to use forEach() and $in operator to do this.
db.projects.find().forEach(
function () {
{
versions: {
$in: ['5cdb24b41a40ae58e6d690fe']
}
}
}
);
But each time I get the following response: Script executed successfully, but there are no results to show. Am I doing this correctly?
There are various solutions you could try, for example:
1) You could add a filter to your find-query:
db.getCollection('debug').find({"versions":{"$in":[ObjectId("5cdb24b41a40ae58e6d690fe")]}})
This would directly return the object you're looking for.
2) If you don't want to pass a filter and really query all documents and filter them yourself, you could try the following:
db.getCollection('debug').find({}).forEach(doc => {
doc.versions.forEach(v => {
if(v.toString() === "ObjectId(\"5cdb24b41a40ae58e6d690fe\")") {
print("match");
}
});
});

Mongoose, query a collection with a set of ObjectID

I'm creating an api with node.js, express and mongoose. I'm pretty new to mongosse and I am wondering if there exists a better way to do what I want.
I have two collections: users and expenses.
User example:
{
"_id" : ObjectId("59c4bc6a39d9992d6407427e"),
"firstName" : "John",
"lastName" : "Doe",
"name" : "JohnD",
"password" : "xxxxx",
"__v" : 26,
"budget" : 400,
"saving" : 300,
"wage" : 1340,
"expenses" : [
ObjectId("59cd076544fa3e64ec32c7e3"),
ObjectId("59cd07f0ed7bd2192cab72bd"),
ObjectId("59cd0a78e19060451059dce7"),
ObjectId("59cd0b24e19060451059dce8"),
ObjectId("59cd0b8fe19060451059dce9"),
ObjectId("59cdf34be19060451059dcf4"),
ObjectId("59cdf3c1e19060451059dcf5"),
ObjectId("59cdf417e19060451059dcf6"),
ObjectId("59cdf446e19060451059dcf7"),
ObjectId("59cdf46ee19060451059dcf8"),
ObjectId("59cdf4bce19060451059dcf9"),
ObjectId("59cdf6dee19060451059dcfa"),
ObjectId("59cdf6f5e19060451059dcfb"),
ObjectId("59cdf768e19060451059dcfc"),
ObjectId("59cdf798e19060451059dcfd"),
ObjectId("59cdf806e19060451059dcfe")
]
}
Expense example:
{
"_id" : ObjectId("59cd07f0ed7bd2192cab72bd"),
"name" : "shopping",
"price" : 100,
"date" : 1506607687013,
"repetition" : 0,
"__v" : 0
}
{
"_id" : ObjectId("59cd0a78e19060451059dce7"),
"name" : "gazoil",
"price" : 50,
"date" : 1506607687013,
"repetition" : 0,
"__v" : 0
}
I want to do a function which takes a user and return all of its expenses. Am I forced to loop through all objectId in user.expenses or there is a proper way to do that directly with mongoose ?
Mongoose has a method for doing what you are willing to do: Query Population
You need to set your schema right and push the refs to the children, then use the populate() method:
const user = await User
.findOne({ _id: 'yourObjId' })
.populate('expenses')
.exec()
console.log(user.stories)
You can use $lookup/aggregate
Check some examples on this answer which seem to explain your use case.
Mongodb, aggregate query with $lookup

If condition does not work / not running

I'm trying to match mongodb object id with if condition:
if (reply[i].data[j].ref == item._id) console.log('match!!!')
The sample of reply & item:
// REPLY
[{
"_id":10,
"data": [
{
"_id":"57f485203858fe43b464ae52",
"type":"product",
"ref":"57f485473858fe43b464ae56",
"name":"KARUNG",
"direction":"in",
"supplier":null,
"information":"PENYESUAIAN JUMLAH",
"qty":200,
"manifest":null,
"timestamp":"2016-10-05T04:44:16.354Z",
"saldo":1200
}
]
}]
// ITEM
{
"_id" : "57f485473858fe43b464ae56",
"name" : "BERAS KC",
"unit" : "SAK",
"qty" : 213,
"weight" : 10
}
I was also trying to convert both to ObjectId using mongojs.ObjectId, but it doesn't work.
The full code snippet: http://pastebin.com/SYTLVWqT

MongoDB return specific fields from array

I want to limit my query's result to a set of fields. This is one of my documents:
{
"_id" : "WA9QRuiWtGsr4amtT",
"status" : 3,
"data" : [
{
"name" : "0",
"value" : "Text ..."
},
{
"name" : "1",
"value" : "12345678"
},
{
"name" : "2",
"value" : "Text"
},
{
"name" : "4",
"value" : "2"
},
{
"name" : "8",
"value" : true
},
{
"name" : "26",
"value" : true
},
],
"userId" : "7ouEumtudgC2HX4fF",
"updatedAt" : NumberLong(1415903962863)
}
I want to limit the output to the status field as well a the first and third data document.
This is what I tried:
Meteor.publish('cases', function () {
var fields = {
currentStatus: 1,
'data.0': 1,
'data.2': 1
};
return Cases.find({}, { fields: fields });
});
Sadly it doesn't work. Something else I found is $elemMatch but it only returns the first element:
data: {
$elemMatch: {
name: {
$in: ['0', '2']
}
}
},
How can I limit the output to these fields?
To display status and data(unlimited) fields try
cases.find({}, {"status":1, "data":1})
This is simple query, to limit "data" output you will need to work harder :)
Get 1 element by data.name (not by position):
cases.find({}, {status:1, "data": {$elemMatch:{name:"0"}}})
Get 1 element by data.name, but from a list of values:
cases.find({}, {status:1, "data": {$elemMatch:{name:{$in:["0", "1"]}}}})
To get close to your question, you may try redact. That is new in Mongodb 2.6.
Or play with $unwind and .aggregate() in previous editions.
So far, I do not see a way to return array elements based on a position.

Categories

Resources