Author: alien

  • Khóa học miễn phí OrientDB – Transactions nhận dự án làm có lương

    OrientDB – Transactions



    Like RDBMS, OrientDB supports transactions ACID properties. A transaction comprises a unit of work performed within a database management system. There are two main reasons to maintain transactions in a database environment.

    • To allow concurrent recovery from failures and keep a database consistent even in case of system failures.

    • To provide isolation between programs accessing a database concurrently.

    By default, the database transaction must follow ACID properties such as Atomic, Consistent, Isolated, and Durable properties. But OrientDB is an ACID compliant database, which means it does not contradict or negate the concept ACID, but it changes its perception while handling the NoSQL database. Take a look at how ACID properties work along with NoSQL database.

    Atomic − When you do something to change the database the change should work or fail as a whole.

    Consistent − The database should remain consistent.

    Isolated − If other transaction executions are executing at the same time, then the user will not be able to see the records in concurrent execution.

    Durable − If the system crashes (hardware or software), the database itself should be able to take a backup.

    Database transaction can be achieved by using Commit and Rollback commands.

    Commit

    Commit means closing the transaction by saving all changes to the database. Rollback means recover the database state to the point where you opened the transaction.

    The following statement is the basic syntax of the COMMIT database command.

    COMMIT
    

    Note − You can use this command only after connecting to a particular database and after beginning the transaction.

    Example

    In this example, we will use the same database named ‘demo’ that we created in an earlier chapter of this tutorial. We will see the operation of commit transaction and store a record using transactions.

    You need to first start the transaction using the following BEGIN command.

    orientdb {db = demo}> BEGIN
    

    Insert a record into an employee table with the values id = 12 and name = satish.P using the following command.

    orientdb> INSERT INTO employee (id, name) VALUES (12, ''satish.P'')
    

    You can use the following command to commit the transaction.

    orientdb> commit
    

    If this transaction successfully committed, you will get the following output.

    Transaction 2 has been committed in 4ms
    

    Rollback

    Rollback means recovering the database state to the point where you opened the transaction.

    The following statement is the basic syntax of the ROLLBACK database command.

    ROLLBACK
    

    Note − You can use this command only after connecting to a particular database and after beginning the transaction.

    Example

    In this example, we will use the same database named ‘demo’ that we created in an earlier chapter of the tutorial. We will see the operation of rollback transaction and store a record using transactions.

    You have to first start the transaction using the following BEGIN command.

    orientdb {db = demo}> BEGIN
    

    Insert a record into an employee table with the values id = 12 and name = satish.P using the following command.

    orientdb> INSERT INTO employee (id, name) VALUES (12, ''satish.P'')
    

    You can use the following command to retrieve the records of the table employee.

    orientdb> SELECT FROM employee WHERE name LIKE ''%.P''
    

    If this command is executed successfully, you will get the following output.

    ---+-------+--------------------
     # | ID   | name
    ---+-------+--------------------
     0 | 12   | satish.P
    ---+-------+--------------------
    1 item(s) found. Query executed in 0.076 sec(s).
    

    You can use the following command to Rollback this transaction.

    orientdb> ROLLBACK
    

    Check the select query again to retrieve the same record from the Employee table.

    orientdb> SELECT FROM employee WHERE name LIKE ''%.P''
    

    If the Rollback is executed successfully, you will get 0 records found in the output.

    0 item(s) found. Query executed in 0.037 sec(s).
    

    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc

  • Khóa học miễn phí OrientDB – Indexes nhận dự án làm có lương

    OrientDB – Indexes



    Index is a pointer which points to a location of data in the database. Indexing is a concept used to quickly locate the data without having to search every record in a database. OrientDB supports four index algorithms and several types within each.

    The four types of index are −

    SB-Tree Index

    It provides a good mix of features available from other index types. Better to use this for general utility. It is durable, transactional and supports range queries. It is default index type. The different type plugins that support this algorithm are −

    • UNIQUE − These indexes do not allow duplicate keys. For composite indexes, this refers to the uniqueness of the composite keys.

    • NOTUNIQUE − These indexes allow duplicate keys.

    • FULLTEXT − These indexes are based on any single word of text. You can use them in queries through the CONTAINSTEXT operator.

    • DICTIONARY − These indexes are similar to those that use UNIQUE, but in the case of duplicate keys, they replace the existing record with the new record.

    Hash Index

    It performs faster and is very light in disk usage. It is durable, transactional, but does not support range queries. It works like HASHMAP, which makes it faster on punctual lookups and it consumes less resources than other index types. The different type plugins that support this algorithm are −

    • UNIQUE_HASH_INDEX − These indexes do not allow duplicate keys. For composite indexes, this refers to the uniqueness of the composite keys.

    • NOTUNIQUE_HASH_INDEX − These indexes allow duplicate keys.

    • FULLTEXT_HASH_INDEX − These indexes are based on any single word of text. You can use them in queries through the CONTAINSTEXT operator.

    • DICTIONARY_HASH_INDEX − These indexes are similar to those that use UNIQUE_HASH_INDEX, but in cases of duplicate keys, they replace the existing record with the new record.

    Lucene Full Text Index

    It provides good full-text indexes, but cannot be used to index other types. It is durable, transactional, and supports range queries.

    Lucene Spatial Index

    It provides good spatial indexes, but cannot be used to index other types. It is durable, transactional, and supports range queries.

    Creating Indexes

    Create index is a command to create an index on a particular schema.

    The following statement is the basic syntax to create an index.

    CREATE INDEX <name> [ON <class-name> (prop-names)] <type> [<key-type>]
    [METADATA {<metadata>}]
    

    Following are the details about the options in the above syntax.

    <name> − Defines the logical name for the index. You can also use the <class.property> notation to create an automatic index bound to a schema property. <class> uses the class of the schema and <property> uses the property created in the class.

    <class-name> − Provides the name of the class that you are creating the automatic index to index. This class must exist in the database.

    <prop-names> − Provides the list of properties, which you want the automatic index to index. These properties must already exist in schema.

    <type> − Provides the algorithm and type of index that you want to create.

    <key-type> − Provides the optional key type with automatic indexes.

    <metadata> − Provides the JSON representation.

    Example

    Try the following query to create automatic index bound to the property ‘ID’ of the user sales_user.

    orientdb> CREATE INDEX indexforID ON sales_user (id) UNIQUE
    

    If the above query is executed successfully, you will get the following output.

    Creating index...
    Index created successfully with 4 entries in 0.021000 sec(s)
    

    Querying Indexes

    You can use select query to get the records in the index.

    Try the following query to retrieve the keys of index named ‘indexforId’.

    SELECT FROM INDEX:indexforId
    

    If the above query is executed successfully, you will get the following output.

    ----+------+----+-----
    #   |@CLASS|key |rid
    ----+------+----+-----
    0   |null  |1   |#11:7
    1   |null  |2   |#11:6
    2   |null  |3   |#11:5
    3   |null  |4   |#11:8
    ----+------+----+-----
    

    Drop Indexes

    If you want to drop a particular index, you can use this command. This operation does not remove linked records.

    The following statement is the basic syntax to drop an index.

    DROP INDEX <name>
    

    Where <name> provides the name of the index you want to drop.

    Try the following query to drop an index named ‘ID’ of user sales_user.

    DROP INDEX sales_users.Id
    

    If the above query is executed successfully, you will get the following output.

    Index dropped successfully
    

    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc

  • Khóa học miễn phí OrientDB – Update Edge nhận dự án làm có lương

    OrientDB – Update Edge



    Update edge command is used to update edge records in the current database. This is equivalent to actual update command in addition to checking and maintaining graph consistency with vertices, in the event that you update the out and in properties.

    The following statement is the basic syntax of Update Edge Command.

    UPDATE EDGE <edge>
       [SET|INCREMENT|ADD|REMOVE|PUT <field-name> = <field-value> [,]*]|[CONTENT|MERGE <JSON>]
       [RETURN <returning> [<returning-expression>]]
       [WHERE <conditions>]
       [LOCK default|record]
       [LIMIT <max-records>] [TIMEOUT <timeout>]
    

    Following are the details about the options in the above syntax.

    <edge> − Defines the edge that you want to update. You can choose between Class that updates edges by class, Cluster that updates edges by cluster, using CLUSTER prefix, or Record ID that updating edges by record ID.

    SET − Updates the field to the given values.

    INCREMENT − Increments the given field by the value.

    ADD − Defines an item to add to a collection of fields.

    REMOVE − Defines an item to remove from a collection of fields.

    PUT − Defines an entry to put into map fields.

    RETURN − Defines the expression you want to return after running the update.

    WHERE − Defines the filter condition.

    LOCK − Defines how the record locks between the load and updates.

    LIMIT − Defines the maximum number of records.

    Example

    Let us consider an example of updating the edge named ‘address’ in the person class by taking data from the address table having area Id = 001, and the person name = Krishna.

    orientdb> UPDATE EDGE address SET out = (SELECT FROM Address WHERE areaID = 001)
    WHERE name = ''krishna''
    

    If the above query is executed successfully, you will get the following output.

    Updated edge ''[address[#10:3][#11:3->#14:2]]'' in 0.012000 sec(s)
    

    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc

  • Khóa học miễn phí OrientDB – Functions nhận dự án làm có lương

    OrientDB – Functions



    This chapter explains the complete reference of different types of functions in OrientDB. The following table defines the list of functions, which are categorized by their functionality.

    Graph Functions

    Try some graph functions along with the following queries.

    Execute the following query to get all the outgoing vertices from all the vehicle vertices.

    orientdb {db = demo}>SELECT out() from Vehicle
    

    If the above query is executed successfully, you will get the following output.

    ---+----------+---------
     # | @class   | out
    ---+----------+---------
     0 | Vehicle  | #11:2
     1 | Vehicle  | #13:1
     2 | Vehicle  | #13:4
    ---+----------+---------
    

    Execute the following query to get both incoming and outgoing vertices from the vertex #11:3.

    orientdb {db = demo}>SELECT both() FROM #11:3
    

    If the above query is executed successfully, you will get the following output.

    ---+----------+--------+-------
     # | @class   | out    | in
    ---+----------+--------+-------
     0 | Vehicle  | #13:2  | #10:2
     ---+----------+-------+-------
    

    Math Functions

    Try some math functions using the following queries.

    Execute the following query to get the sum of salaries of all employees.

    orientdb {db = demo}>SELECT SUM(salary) FROM Employee
    

    If the above query is executed successfully, you will get the following output.

    ---+----------+---------
     # | @CLASS   | sum
    ---+----------+---------
     0 | null     | 150000
    ---+----------+---------
    

    Execute the following query to get the average salary of all employees.

    orientdb {db = demo}>SELECT avg(salary) FROM Employee
    

    If the above query is executed successfully, you will get the following output.

    ---+----------+---------
     # | @CLASS   | avg
    ---+----------+---------
     0 | null     | 25
    ---+----------+---------
    

    Collections Functions

    Try some collection functions using the following queries.

    Execute the following query to get a set of teachers, teaching class 9th.

    orientdb {db = demo}>SELECT ID, set(teacher.id) AS teacherID from classess where class_id = 9
    

    If the above query is executed successfully, you will get the following output.

    ---+----------+--------+--------------------------
     # | @CLASS   | id     | TeacherID
    ---+----------+--------+--------------------------
     0 | null     | 9     |   1201, 1202, 1205, 1208
    ---+----------+-------+---------------------------
    

    Misc Functions

    Try some Misc functions using the following queries.

    Execute the following query to learn how to execute if expression.

    orientdb {db = demo}> SELECT if(eval("name = ''satish''"), "My name is satish",
    "My name is not satish") FROM Employee
    

    If the above query is executed successfully, you will get the following output.

    ----+--------+-----------------------
    #   |@CLASS  | IF
    ----+--------+-----------------------
    0   |null    |My name is satish
    1   |null    |My name is not satish
    2   |null    |My name is not satish
    3   |null    |My name is not satish
    4   |null    |My name is not satish
    ----+--------+------------------------
    

    Execute the following query to get system date.

    orientdb {db = demo}> SELECT SYSDATE() FROM Employee
    

    If the above query is executed successfully, you will get the following output.

    ----+--------+-----------------------
    #   |@CLASS  | SYSDATE
    ----+--------+-----------------------
    0   |null    |2016-02-10 12:05:06
    1   |null    |2016-02-10 12:05:06
    2   |null    |2016-02-10 12:05:06
    3   |null    |2016-02-10 12:05:06
    4   |null    |2016-02-10 12:05:06
    ----+--------+------------------------
    

    By using this function thoroughly you can easily manipulate the OrientDB data.


    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc

  • Khóa học miễn phí OrientDB – Delete Edge nhận dự án làm có lương

    OrientDB – Delete Edge



    Delete edge command is used to remove the database. This is equivalent of the delete command, with the addition of checking and maintaining consistency with vertices by removing all cross-references to the edge from both ‘in’ and ‘out’ vertex properties.

    The following statement is the basic syntax of Delete Edge command.

    DELETE EDGE
       ( <rid>
          |
          [<rid> (, <rid>)*]
          |
          ( [ FROM (<rid> | <select_statement> ) ] [ TO ( <rid> | <select_statement> ) ] )
          |
          [<class>]
       (
          [WHERE <conditions>]
          [LIMIT <MaxRecords>]
          [BATCH <batch-size>]
       ))
    
    

    Following are the details about the options in the above syntax.

    FROM − Defines the starting point vertex of the edge to delete.

    To − Defines the ending point vertex of the edge to delete.

    WHERE − Defines the filtering conditions.

    LIMIT − Defines the maximum number of edges to delete.

    BATCH − Defines the block size for the operation.

    Example

    Try the following examples to learn how to delete edges.

    Execute the following query to delete the edge between two vertices (#11:2, #11:10). But there might be a chance that might exist one or more edges between two vertices. So that we are using the date property for proper functionality. This query will delete the edges which are created on ”2015-01-15” and later.

    orientdb {db = demo}> DELETE EDGE FROM #11:2 TO #11:10 WHERE date >= "2012-01-15"
    

    If the above query is executed successfully, you will get the following output.

    Delete record(s) ''2'' in 0.00200 sec(s)
    

    Execute the following query to delete edges starting from the vertex ‘#11:5’ to the vertex ‘#11:10’ and which are related to ‘class = Customer’.

    orientdb {db = demo}> DELETE EDGE FROM #11:5 TO #11:10 WHERE @class = ''Customer''
    

    If the above query is executed successfully, you will get the following output.

    Delete record(s) ''2'' in 0.00200 sec(s)
    

    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc

  • Khóa học miễn phí OrientDB – Create Edge nhận dự án làm có lương

    OrientDB – Create Edge



    In OrientDB, the concept Edge works like a relation between vertices with the help of some properties. Edges and vertices are the main components of a graph database. It applies polymorphism on Edges. The base class for an Edge is E. While implementing edges, if source or destination vertices are missing or don’t exist, then the transaction will be rollback.

    The following statement is the basic syntax of Create Edge Command.

    CREATE EDGE <class> [CLUSTER <cluster>] FROM <rid>|(<query>)|[<rid>]* TO <rid>|(<query>)|[<rid>]*
         [SET <field> = <expression>[,]*]|CONTENT {<JSON>}
         [RETRY <retry> [WAIT <pauseBetweenRetriesInMs]] [BATCH <batch-size>]
    

    Following are the details about the options in the above syntax.

    <class> − Defines the class name for the edge.

    <cluster> − Defines the cluster in which you want to store the edge.

    JSON − Provides JSON content to set as the record.

    RETRY − Defines the number of retries to attempt in the event of conflict.

    WAIT − Defines the time to delay between retries in milliseconds.

    BATCH − Defines whether it breaks the command down into smaller blocks and the size of the batches.

    Example

    Execute the following query to create an edge E between two vertices #9:0 and #14:0.

    orientdb> CREATE EDGE FROM #11:4 TO #13:2
    

    If the above query is executed successfully, you will get the following output.

    Created edge ''[e[#10:0][#9:0->#14:0]]'' in 0.012000 sec(s)
    

    Execute the following query to create a new edge type and an edge of new type.

    orientdb> CREATE CLASS E1 EXTENDS E
    orientdb> CREATE EDGE E1 FROM #10:3 TO #11:4
    

    If the above query is executed successfully, you will get the following output.

    Created edge ''[e[#10:1][#10:3->#11:4]]'' in 0.011000 sec(s)
    

    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc

  • Khóa học miễn phí OrientDB – Sequences nhận dự án làm có lương

    OrientDB – Sequences



    Sequences is a concept used in auto increment mechanism and it is introduced in OrientDB v2.2. In database terminology, sequence is a structure that manages the counter field. Simply said sequences are mostly used when you need a number that always increments. It supports two types−

    ORDERED − Each time the pointer calls the .next method that returns a new value.

    CACHED − The sequence will cache ‘N’ items on each node. To call each item we use .next(), which is preferred when the cache contains more than one item.

    Create Sequence

    Sequence is usually used to auto increment the id value of a person. Like other SQL concepts of OrientDB it also preforms similar operations as Sequence in RDBMS.

    The following statement is the basic syntax to create sequences.

    CREATE SEQUENCE <sequence> TYPE <CACHED|ORDERED> [START <start>]
    [INCREMENT <increment>] [CACHE <cache>]
    

    Following are the details about the options in the above syntax.

    <Sequence> − Local name for sequence.

    TYPE − Defines the sequence type ORDERED or CACHED.

    START − Defines the initial value.

    INCREMENT − Defines the increment for each .next method call.

    CACHE − Defines the number of value to pre-cache, in the event that you used to cache sequence type.

    Let us create a sequence named ‘seqid’ which starts with number 1201. Try the following queries to implement this example with sequence.

    CREATE SEQUENCE seqid START 1201
    

    If the above query is executed successfully, you will get the following output.

    Sequence created successfully
    

    Try the following query to use sequence ‘seqid’ to insert the id value of Account table.

    INSERT INTO Account SET id = sequence(''seqid'').next()
    

    If the above query is executed successfully, you will get the following output.

    Insert 1 record(s) in 0.001000 sec(s)
    

    Alter Sequence

    Alter sequence is a command used to change the properties of a sequence. It will modify all the sequence options except sequence type.

    The following statement is the basic syntax to alter sequence.

    ALTER SEQUENCE <sequence> [START <start-point>]
    [INCREMENT <increment>] [CACHE <cache>]
    

    Following are the details about the options in the above syntax.

    <Sequence> − Defines the sequence you want to change.

    START − Defines the initial value.

    INCREMENT − Defines the increment for each .next method call.

    CACHE − Defines the number of value to pre-cache in the event that you used to cache sequence type.

    Try the following query to alter the start value from ‘1201 to 1000’ of a sequence named seqid.

    ALTER SEQUENCE seqid START 1000
    

    If the above query is executed successfully, you will get the following output.

    Altered sequence successfully
    

    Drop Sequence

    Drop sequence is a command used to drop a sequence.

    The following statement is the basic syntax to drop a sequence.

    DROP SEQUENCE <sequence>
    

    Where <Sequence> defines the sequence you want to drop.

    Try the following query to drop a sequence named ‘seqid’.

    DROP SEQUENCE seqid
    

    If the above query is executed successfully, you will get the following output.

    Sequence dropped successfully
    

    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc

  • Khóa học miễn phí OrientDB – Drop Property nhận dự án làm có lương

    OrientDB – Drop Property



    The Drop property command removes the property from the schema. It does not remove the property values from the record, it just change the schema.

    The following statement is the basic syntax of Drop Property Command.

    DROP PROPERTY <class>.<property> [FORCE]
    

    Following are the details about the options in the above syntax.

    <class> − Defines the class where the property exists.

    <property> − Defines the property you want to remove.

    [Force] − In case one or more indexes are defined on the property.

    Example

    Try the following command to remove ‘age’ property from the class ‘Customer’.

    orientdb> DROP PROPERTY Customer.age
    

    If the above command is executed successfully, you will get the following output.

    Property dropped successfully
    

    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc

  • Khóa học miễn phí OrientDB – Create Vertex nhận dự án làm có lương

    OrientDB – Create Vertex



    OrientDB database is not only a Document database but also a Graph database. New concepts such as Vertex and Edge are used to store the data in the form of graph. It applies polymorphism on vertices. The base class for Vertex is V.

    In this chapter you can learn how to create vertex to store graph data.

    The following statement is the basic syntax of Create Vertex Command.

    CREATE VERTEX [<class>] [CLUSTER <cluster>] [SET <field> = <expression>[,]*]
    

    Following are the details about the options in the above syntax.

    <class> − Defines the class to which the vertex belongs.

    <cluster> − Defines the cluster in which it stores the vertex.

    <field> − Defines the field you want to set.

    <expression> − Defines the express to set for the field.

    Example

    Try the following example to understand how to create vertex.

    Execute the following query to create a vertex without ‘name’ and on the base class V.

    orientdb> CREATE VERTEX
    

    If the above query is executed successfully, you will get the following output.

    Created vertex ''V#9:0 v1'' in 0.118000 sec(s)
    

    Execute the following query to create a new vertex class named v1, then create vertex in that class.

    orientdb> CREATE CLASS V1 EXTENDS V
    orientdb> CREATE VERTEX V1
    

    If the above query is executed successfully, you will get the following output.

    Created vertex ''V1#14:0 v1'' in 0.004000 sec(s)
    

    Execute the following query to create a new vertex of the class named v1, defining its properties such as brand = ”Maruti” and name = ”Swift”.

    orientdb> CREATE VERTEX V1 SET brand = ''maruti'', name = ''swift''
    

    If the above query is executed successfully, you will get the following output.

    Created vertex ''V1#14:1{brand:maruti,name:swift} v1'' in 0.004000 sec(s)
    

    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc

  • Khóa học miễn phí OrientDB – Move Vertex nhận dự án làm có lương

    OrientDB – Move Vertex



    Move Vertex command in OrientDB is to move one or more vertices from current location to different class or cluster. If you are applying move command on a particular vertex, then it will update all the edges that are connected to this vertex. If you are specifying a cluster to move vertex, then it moves the vertices to the server owner of the target cluster.

    The following statement is the basic syntax of Move Vertex Command.

    MOVE VERTEX <source> TO <destination>
    [SET [<field>=<value>]* [,]]
    [MERGE <JSON>]
    [BATCH <batch-size>]
    

    Following are the details about the options in the above syntax.

    <source> − Defines the vertex you want to move. It accepts Record ID of a particular vertex or array of Record IDs for vertices.

    <destination> − Defines where you want to move the vertex. It supports either class or a cluster as destination.

    SET − Sets the values to fields.

    MERGE − Sets the values to fields through JSON.

    BATCH − Defines the batch size.

    Note − This command updates all connected edges, but not links. When using Graph API, it is recommended to use edge connected to vertices.

    Example

    Try the following examples to learn how to move vertices.

    Execute the following query to move a single vertex having Record ID #11:2 from its current position to Class Employee.

    orientdb> MOVE VERTEX #11:2 TO CLASS:Employee
    

    If the above query is executed successfully, you will get the following output −

    Move vertex command executed with result ''[{old:#11:2, new:#13:0}]'' in 0.022000 sec(s)
    

    Execute the following query to move set of vertices from the class ‘Customer’ to class ‘Employee’.

    orientdb> MOVE VERTEX (SELECT FROM Customer) TO CLASS:Employee
    

    If the above query is executed successfully, you will get the following output.

    Move vertex command executed with result ''[{old:#11:0,
    new:#13:1},{old:#11:1, new:#13:2},{old:#11:2, new:#13:3}]'' in 0.011000 sec(s)
    

    Khóa học lập trình tại Toidayhoc vừa học vừa làm dự án vừa nhận lương: Khóa học lập trình nhận lương tại trung tâm Toidayhoc